Java 异常处理
一、Java异常机制介绍
1、Java的异常处理机制
程序失效的原因多种多样,不良输入和程序逻辑错误只是多种可能中的两个。所以程序应该用可预测的方式处理失败。
处理程序失效包括两个方面:监测和恢复。
Java语言在设计之初就考虑到了这些问题,提出了异常处理框架的解决方案,所有的异常都用类来表示,不同类型的异常的对应不同的异常处理流程。异常处理提供了一种识别及响应错误情况的一致性机制,有效的异常处理能使程序逻辑更加清晰、健壮并且易于调试和跟踪。
异常处理机制回答了三个问题:
- 程序中什么出错了?---异常类型
- 在哪出的错?---异常栈跟踪回答
- 为什么会出错?---异常信息
2、Java对异常的处理
Java对异常的处理是分类进行的,每个异常都是一个异常类的对象。
程序运行出现意外时,系统会生成一个Exception对象并自动进行错误处理匹配,根据异常类型进入不同的处理分支。
3、异常处理机制的关键字
1) try…catch:
可能引发异常的代码块放置在try和catch之间,从而要求JVM监测该代码块的执行。catch块用于处理特定类型的异常,try后可以有多个catch处理块。
2) finally:
用于回收再try块里打开的物理资源(数据库连接、网络连接和磁盘文件等),异常机制保证finally块总是被执行。
3) throw:
从方法代码块中主动抛出一个实际的异常对象。
4) throws:
在方法签名中申明(该方法可能抛出多个)异常。
4、异常架构
所有非正常情况分为两种:异常(Exception)和错误(Error),均继承自类Throwable。
错误:是指虚拟机相关问题如系统崩溃、虚拟机出错等,这类错误无法恢复,程序也不用捕获了。
异常:异常分为两大类:受查异常(Checked)和运行时异常(Runtime)。
运行时异常:
所有运行时异常类和它的子类的对象被称为运行时异常。运行时异常不需要显示声明抛出,如果程序需要捕捉运行时异常,可以用try…catch块。
受查异常:
不是运行时异常实例都归为受查异常,它是可以被修复的异常。程序必须显示地处理受查异常,如果没有处理,在编译时就无法通过。
必须用try…catch块捕获,在catch中修复。当方法不知道如何处理,在定义方法时声明抛出(throws)异常,由上一级调用处理。
5、异常对象和异常抛出
异常对象:包含了异常的上下文信息,定义了常用方法来获得这些信息。
异常抛出:异常必须被传递出去或者被处理掉,否则编译时编译器会报告错误。
异常抛出的处理流程:抛出-传递-处理。
首先,在异常发生的位置创建描述异常的对象,并将该对象使用throw抛出;
然后,异常传递从throw语句开始,被传递到调用该方法的位置,并不断沿着调用栈向上传递,直到main()方法,或者中途被某一层捕捉并处理。
二、异常处理
1、try...catch...
try…catch实现正常业务逻辑和异常逻辑的分离。
try…catch块是如何工作的?
try块里代码执行时产生异常,会生成一个异常对象,该异常对象被提交给JVM,即异常被抛出;JVM收到异常对象后,寻找合适的catch代码块,进行匹配,匹配规则是:catch语句中的异常类型必须是当前异常对象类型或者它的父类型;若找不到,程序会退出。
关于异常处理的三点提示:
- 不管程序代码块是否处于try块中,只要任何代码出现了异常,都会生成一个异常对象。
- 可以用多个catch块处理不同的异常。
- 异常捕获先捕获小的异常,再捕获大的。即先捕获异常类中靠近叶子节点的异常。
2、finally
处理异常会使程序中断并直接进入异常处理模块,异常点后的代码不会被执行。
为了保证某些功能完成,如资源的释放,使用finally语句块,即一定会被执行的代码。
3、捕获异常
try块是必须的,catch块和finally块至少选其一。
多个catch块捕获异常时,捕获子类异常的catch块应该在前面,捕获父类异常的块应该在后面。
4、throws声明异常:
当不确定如何处理异常,需要声明异常。
throws可以同时声明多个异常,声明后就不需要在当前代码块中使用try…catch结构。因为使用了throws声明,就意味着该方法希望它的调用者处理这些异常。
5、throw抛出异常对象:
可以在程序中使用throw语句自行抛出一个异常实例,调用者可以显示捕获也可以不理会。
6、异常转译
面对开发者和客户应该显示不同的异常信息。
7、自定义异常
自定义异常应该继承基类Exception。
8、异常处理原则
- 具体明确
- 尽早抛出
- 延迟捕获
- 开发者可以自定义异常,优雅地处理
9、注意事项
- 异常捕获之后应进行一定的处理;
- 抛出的异常应该尽量具体;
- 充分运用finally保证资源释放完成;
- 提供最有价值的异常信息,不能太空泛;
- 不应将大量代码放入单个try块,因为当中可能有多个地方抛出异常。正确的做法是分离各个可能出现异常的段落并分别捕获异常