9、异常处理
异常处理
1、异常概述和异常体系结构
异常的分类:「error」,「exception」
- 编译时异常必须显式处理
- 运行时异常交给虚拟机
//Error
public class ErrorTest{
public static void main(String[] args){
//1、栈溢出:java.lang.StackOverflowError
main(args);
//2、堆溢出:java.lang.OutOfMemoryError
Integer[] arr = new Integer[1024*1024*1024];
}
}
- 蓝色:运行时异常(unchecked)
- 红色:编译时异常(checked)
一、异常体系结构:
2、Java 异常处理的方式
方式一:try - catch - finally
方式二:throws + 异常类型
异常的处理
- 程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应「异常对象」,并将此对象抛出。
- 一旦抛出对象后,其后的代码就不在执行(catch 中,异常后的代码不执行)
可以理解为异常的处理方式:
- try-catch-finally
- throws
异常对象可以调用如下方法得到或输出异常的信息:
public String getMessage();
public void printStackTrace();
public String toString();
1、try-catch-finally 的使用
try{
//可能出现异常的代码
}catch(异常类型1 变量名1){
//处理异常的方式1
}catch(异常类型2 变量名2){
//处理异常的方式2
}catch(异常类型3 变量名3){
//处理异常的方式3
}
......
finally{
//一定会执行的代码
}
public void test1{
String str = "abc";
try{
int num = Integer.parseInt(str);// 出现异常,直接进入catch
System.out.println("1");
}catch(NumberFormatException e){
System.out.println(e.getMessage());
e.printStakeTracce();
System.out.println("出现数值转换异常");
}
System.out.println("2"); // 输出
}
说明:
- finally 是可选的
- 使用 try 将可能出现异常的代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中匹配
- 一旦 try 中异常对象匹配到某一个 catch ,进入 catch 中进行异常处理。一旦处理完成,就跳出 try-catch 结构(在没有写 finally 的情况)。继续执行其后的代码
- catch 中异常类型注意子父类、先后顺序。父类声明在子类之上,报错。
- 常用的异常对象处理方式:① String getMessage() ②printStakeTracce()
- 在 try 结构中声明的变量,出了 try 结构后,就不能再被调用。
- try-catch-finally 结构可以相互嵌套
体会:
使用 try-catch-finally 处理编译时异常,将编译时异常转换为运行时异常,延迟出现。
由于运行时异常比较常见,不针对运行时异常编写 try-catch-finally。
针对编译时异常,一定要考虑 try-catch-finally
try-catch-finally 中 finally 的使用
- finally 是可选的
- finally 中声明的是一定会被执行的代码。即使catch中又出现了异常, try 中有 return 语句, catch 中有 return 语句等情况
- 像数据库连接、输入输出流、网络编程 Socket 等资源,jvm 是不能自动回收的,我们需要手动进行资源的释放,此时资源释放就需要声明在 finally 中。
- try-catch 语句中执行了程序退出代码
System.exit(0)
则不执行 finally 子语句
public class FinallyTest{
public void test1(){
try{
int a = 10;
int b = 0;
System.out.println(a/b);
}catch(ArithmeticExceptioin e){
e.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}finally{
System.out.prinln("");
}
}
}
2、throws + 异常类型
1、throws + 异常类型
写在方法的声明处,指明此方法执行时,可能会抛出的异常类型。
一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足 throws 后异常类型时,就会被抛出。异常代码后续的代码就不再执行。
2、try-catch-finally
:真正的将异常处理掉。throws
只是将异常抛给了方法的调用者。并没有将异常处理掉
public void ExceptionTest2{
public void method1() throws FileNotFoundException,IOException{
//异常
}
public void method2() throws IoException{
method1();
}
}
}
方法重写的规则之一:
子类重写的方法抛出的异常不大于父类被重写的方法抛出的异常类型
3、try-catch-finally 和 throws 的选择
- 如果父类中被重写的方法没有 throws 方式处理异常,则子类重写的方法也不能使用 throws ,意味着如果子类重写的方法中有异常,必须使用 try-catch-finally 方式处理。
- 执行的方法 a 中先后又调用了另外几个方法,这几个方法是递进关系执行的,建议这几个方法使用 throws 的方式 进行处理。而执行的方法 a 可以考虑 try-catch-finally 方式进行胡成立
3、手动抛出异常对象
关于异常对象的产生:
- 系统自动生成的异常对象
- 手动生成并抛出一个异常对象(throw)
相关信息
throws 和 throw 的区别:
throw 表示抛出一个异常的对象,生成异常对象的过程,声明在方法体内 throw new 异常类("abc")
throws 属于异常处理的一种方式,声明在方法的声明处
public static void mian(String[] args){
Student s = new Student();
s.regist(-1001);//最后try-catch一下
System.out.println(s);
}
class Student{
private int id;
public void regist(int id) throws Exception{
if(id > 0){
this.id = id;
}else{
//System.out.pringln("非法");
//手动抛出异常
//throw new RuntimeException("您输入的数据非法");
throw new Exception("您输入的数据非法");
}
}
}
4、自定义异常类
自定义异常类:
- 继承于现有的异常结构:Exception、RuntimeException
- 提供重载的构造器
- 提供全局变量:serialVersionUID(可省略)
public class MyException extends RuntimeException{
static final long serialVersionUID = -61641614198984L;
public MyException(){
}
public MyException(String msg){
//super(msg);
ms = "出现异常";
}
}
5、断言语句
断言语句用于在代码调试阶段发生错误时,要求程序必须立即停止执行
使用关键字「assert」声明一条断言语句
断言语句的两种格式:
assert booleanExpression;
assert booleanExpression:messageException;
booleanExpression
为 boolean 类型,当其值为 false 时,程序从断言语句处停止执行,若有 messageException ,输出信息