我觉得 Java 的异常处理要精简 , 因为 , 处理异常需要 JVM 付出额外的开销 .Java 异常的根类为 java.lang.Throwable, 其有两个直接的子类 :java.lang.Error 和 java.lang.Exception. Error 表示程序本身无法恢复的严重错误 ;Exception 类表示可以被程序捕获并处理的 Bug. 我们也可以自定义类来抛出异常 , 但是都必须直接或间接继承 Exception 类 .
(一) 错误处理与 JVM 用方法调用堆栈
MethodB() |
MethodA() |
Main() |
MethodB() |
MethodA() |
Main() |
如果这个时候 , 方法中的代码可能抛出异常 , 将会有两种处理
MethodB() |
MethodA() |
Main() |
MethodB() |
MethodA() |
Main() |
方法 :
1).
Public void methodB(int a) {
Try{
//do
If(a<0) throw new SpecialException();
}catch(SpecialException e){
MethodB() |
MethodA() |
Main() |
//do with Exception
}
}
2). 在方法的声明处通过 throws 语句声明抛出异常 , 如 :
Public void mothodB(int a) throws SpecialException{
//do
If(a<0) throw new SpecialException();
}
当 java 的方法正常执行完毕 ,JVM 会从 Stack 中弹出该方法的栈结构 , 然后继续处理前一个方法 . 如果 java 方法在执行代码过程中抛出异常 ,JVM 必须找到能捕获该异常的 Catch 代码块 . 他首先查看当前方法是否存在这样的 Catch 代码块 , 如果存在 , 就执行 catch 代码 , 否则 ,JVM 会从调用栈中弹出该方法的栈结构 , 继续到前一个方法中查找合适的 catch 代码块 .
例如 : 当 MethodB() 方法抛出 SpecialException 时 , 如果在该方法中提供了捕获 SpecialException 的 Catch 代码块 , 就执行这个异常处理代码块 , 否则 , 如果采用第二种方式声明继续抛出 SpecialException,JVM 的处理流程将退回到上层调用方法 MethodA(), 再查看 A 有没有捕获 SpecialException. 如果 ,A 方法中存在捕获 SpecialException 的 catch 代码块 , 就执行 . 此时 A 方法定义如下 :
Public void methodA(int a){
Try{
methodB(a);
}catch(SpecialException e){
//do with Exception
}}
如果 ,A 方法也没有捕获 SpecialException, 而只是声明抛出 SpecialException,JVM 处理流程将继续退回到 main() 方法 . 如果 ,main() 里面仍然没有找到处理该异常的代码 , 该线程就会异常终止 . 如果 , 该线程是主线程 , 应用程序也会终止 . 用户终端就会看到原始异常信息 .
一般说来,在 java 程序中使用 try/catch 不会对应用程序有很大的影响,仅仅当异常发生时, JVM 虚拟执行额外的操作,来定位处理异常的代码块,这时,对系统性能产生负面影响。但是,如果抛出异常的代码和捕获异常的代码在一个方法中,这种影响就会小些,因此,不应该用异常处理机制来控制程序的正常流程,而应该仅仅用在程序可能出现异常的地方才使用 try/catch 。