Java SE第10章 异常处理
- 1. 异常的定义和概念
- 2. Java 异常机制的优势
- 3. 使用try … catch 捕获异常
- 4. 多异常捕获
- 5. Java 异常类的继承体系
- 6. 异常对象的常用方法
- 7. finally块的作用
- 8. 自动关闭资源的try语句
- 9.异常处理的合理嵌套
- 10. Checked异常和Runtime异常
- 11. 使用throws声明异常
- 12. 使用throw抛出异常
- 13. 自定义异常
- 14. 异常链和异常转译
- 15. 异常的跟踪栈信息
- 16. 异常的处理规则
1. 异常的定义和概念
java将异常分为两种:Checked异常和Runtime异常,java认为 Checked异常是可以在编译阶段被处理的异常,Runtime是运行时异常
2. Java 异常机制的优势
java的异常处理机制可以让程序有较好的容错性,让程序更加健壮,当程序出现意外情形时,系统会自动生成一个 Exception对象来通知程序,从而实现将 ”业务功能实现代码“和”错误处理代码“分离,提供更好的可读性
3. 使用try … catch 捕获异常
try{
//业务实现代码
}
catch (Exception e){
//异常处理
}
如果业务实现代码出现异常,会寻找能处理该异常对象的 catch块,如果找到合适的catch块,就把该异常对象交给该catch块处理,这个过程称为捕获异常,如果java运行时环境找不到捕获异常的catch块,则运行时环境终止,java程序也退出
注意:try块中声明的变量是代码块内局部变量,只在try块中有效,在 catch块中不能访问
捕获异常时,一定先捕获小异常,再捕获大异常
4. 多异常捕获
从 java 7开始,一个 catch块可以捕获多种类型的异常
注意
- 捕获多种异常时,多种异常类型之间用 | 隔开
- 捕获多种异常时,异常变量有隐式的 final修饰,因此程序不能对异常变量重新赋值
try{
//balabala
}
catch(IndexOutOfBoundsException | NumberFormatException | ArithmeticException ie){
//捕获多异常时,异常变量默认有 final修饰
ie = new ArithmeticException("一个异常");//报错
}
5. Java 异常类的继承体系
java把所有的非正常情况分为两种:异常(Exception)和错误(Error),Error错误:一般指与虚拟机相关的问题,无法恢复或不可能捕获,将导致应用程序中断,通常应用程序无法处理这些错误,因此应用程序不应该试图catch这些Error对象
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nJzafigt-1649468928105)(C:\Users\shang\Desktop\java\异常继承类.webp)]
6. 异常对象的常用方法
所有的异常对象都包含了几个常用方法
- **getMessage():**返回该异常的详细描述字符串
- **printStackTrace():**将该异常的跟踪栈信息输出到标准错误输出
- **printStackTrace(PrintStream s):**将该异常的跟踪栈信息输出到指定输出流
- **getStackTrace():**返回该异常的跟踪栈信息
7. finally块的作用
使用 finally回收资源
java垃圾回收机制不会回收任何物理资源,垃圾回收机制只能回收堆内存中对象所占的内存
如果 try块的某条语句引起了异常,该语句后的其他语句通常不会获得执行的机会,这将导致不能及时回收这些物理资源,所以提供了 finally块,不管try中是否出现异常,不管哪个catch块被执行,甚至在 try和catch块执行了return 语句,finally块总会执行
异常处理语法只有 try是必须的
如果在异常处理代码中使用 **System.exit(1)**来退出虚拟机,则 finally块会失去执行机会
8. 自动关闭资源的try语句
一旦在 finally块中使用的 return 或 throw 语句,将会导致 try块,catch块中的 return ,throw语句失效
try{
return true;//失效
}
finally{
return false;
}
java 7增强了 try语句的功能,允许在 try关键字后紧跟一对圆括号,圆括号内可以声明,初始化一个或多个资源,此处的资源指的是那些必须在程序结束时显式关闭的资源,try语句在该语句结束自动关闭这些资源
为了保证 try语句可以正常关闭资源,这些资源实现类必须实现 AutoCloseable或 Closeable接口,实现这两个接口就必须实现 **close()**方法
Colseable接口是 AutoCloseable的子接口,Closeable接口里的 close()方法声明抛出了 IOException ,因此它的实现类在实现 close()方法时只能声明抛出 IOException或其子类,AutoCloseable 接口里的 close()方法声明抛出了 Exception,因此它的实现类在实现 close()方法时可以声明抛出任何异常
try(
//初始化可以自动关闭的资源)
{
//使用这个资源
}
java 9 再次增强了 try语句,不要求在try后的圆括号声明并创建资源,只需要自动关闭的资源有 final修饰或者是有效的 final,Java 9 允许将资源变量放 try 后的圆括号内
//定义 final修饰的资源 br
try(br){ //只需将这个资源放在 try后的括号内
//使用 br
}
10. Checked异常和Runtime异常
所有的 RuntimeException类及其子类的实例被称为 Runtime异常,其余异常实例被称为 Checked异常
java 语言必须显式处理 Checked异常,否则无法通过编译
11. 使用throws声明异常
如果当前方法不知道如何处理这种类型的异常,该异常应该由上一级调用者处理,如果 main方法也不知道如何处理这种类型的异常,也可以 使用 throws声明抛出异常,该异常将交给 JVM处理,JVM对异常的处理方法是,打印异常的跟踪栈信息,并中止程序运行
throws声明抛出只能在方法签名中使用, throws可以声明抛出多个异常类,多个异常类之间以逗号隔开
throws ExceptionClass1, ExceptionClass2
一旦 thorws抛出异常,就不用try…catch捕获该异常了
throws抛出异常规则
子类方法声明抛出的异常类型应该是父类方法声明抛出的异常类型的子类或相同,子类方法声明抛出的异常不允许比父类声明抛出的异常多
12. 使用throw抛出异常
当程序出现错误时,系统会自动抛出异常,除此之外,java也允许程序自行抛出异常,自行抛出的异常使用 throw语句完成
throw抛出的不是异常类,而是一个异常实例,而且每次只能抛出一个异常实例
java运行时接收到开发者自行抛出的异常时,同样会中止当前的执行流,跳到该异常对应的 catch块,如果 throw语句抛出的异常 是 Checked异常,则该 throw语句要么处于 try块里,显式捕获该异常,要么放在一个带throws声明抛出的方法中,如果 throw语句抛出的是 Runtime异常,则该语句无需放在try块或throws声明抛出的方法里,程序可以显式使用try…catch捕获该异常,也可以完全不理会该异常,把该异常交给该方法的调用者处理
13. 自定义异常
用户自定义的异常都应该继承 Exception基类,如果希望自定义 Runtime异常,应该继承 RuntimeException基类,定义异常类时通常需要提供两个构造器:无参构造器和带一个字符串参数的构造器,这个字符串将作为该异常对象的描述信息(getMessage())的返回值
public class MyException extends Exception{
//无参构造器
public MyException(){
}
//带一个字符串参数的构造器
public MyException(Strign msg){
super(msg);
}
}
如果需要几个方法协作处理某个异常,可以在一个方法部分处理异常后再抛出该异常,在调用此方法的地方try…catch再处理此异常
对于如下代码
try{
new FileOutputStream("这咋还没写完.txt");
}
catch (Exception e){
ex.printStackTrace();
throw e;
}
在java 7之前,java编译器会认为这个异常类型是 Exception
从java 7开始,java编译器会执行更细致的检查,会认为这个异常类型是 FileNotFoundException
14. 异常链和异常转译
异常转译是程序先捕获原始异常,然后抛出一个新的业务异常,新的业务异常包含了对用户的提示信息
这样处理是为了不把底层的原始异常直接传给用户,把原始异常信息隐藏起来,仅向上提供必要的异常提示信息的处理方式,可以保证底层异常不会扩散到表现层
这种把捕获一个异常然后接着抛出另一个异常,并把原始异常信息保存下来是一种典型的链式处理,也被称为异常链
从 JDK 1.4之后,所有 Throwable的子类在构造器都可以接收一个 cause对象作为参数,这个 cause就用来表示原始异常,这样可以把原始异常传递给新的异常
try{
}
catch(Exception e){
throw new SalException(e);
}
15. 异常的跟踪栈信息
第一行的信息详细显示了异常的类型和异常的详细信息
接下来跟踪栈记录程序所有的异常发生点,各行显示被调用方法中执行的停止位置,并标明类,类中的方法名,与故障点对应的文件的行。一行行往下看,跟踪栈总是最内部的被调用方法逐渐上传,直到最外部业务操作的起点,通常就是程序的入口main方法或 Thread类的run方法
依次
异常源头
第一个
第二个
main方法
16. 异常的处理规则
成功的异常处理应该实现如下四个目标
使程序代码混乱最小化
捕获并保留诊断信息
通知合适人员
采用合适的方式结束异常活动
只有对外部的,不能确定的和预知的运行错误才使用异常
异常只应该用于处理非正常的情况
不要使用过于庞大的try块
避免使用 Catch All语句
try{
}
catch (Throwable t){
}
这种可以捕获所有的异常,但对所有的异常都采用相同处理方式,无法方便分情况处理
这种捕获方式可能会将程序中的错误,Runtime异常等可能导致程序终止的情况全部捕获到,从而会忽略一些异常
不要忽略捕获到的异常,不知道怎么处理就抛出就可以