上期我们分享了Java中日志的处理(下):Java中日志实际使用中的相关注意点
本期我们将分享Java中异常的处理
异常定义
在《java编程思想》中这样定义异常:阻止当前方法或作用域继续执行的问题。
异常分类
首先我们看下Java中异常的继承关系:
可以看出,Throwable
有两个子类:Error
和Exception
Error
- VirtualMachineError,典型的有
StackOverFlow
和OutOfMemory
- AWTError
- VirtualMachineError,典型的有
Exception
- IOException
- ...
- RuntimeException
Exception分为CheckedException和UncheckedException,那么CheckedException和UncheckedException区别是什么呢?
UncheckedException
:派生于Error或者RuntimeException的异常CheckedException
:所有其他的异常
异常处理机制
异常处理机制分为:抛出异常和捕捉异常
抛出异常:方法上使用throws
,方法内使用throw
捕捉异常:使用try-catch
或者try-catch-finally
原则,正如手册上所说:
- 不要直接忽略异常
- 不要用try-catch包住太多语句
- 不要用异常处理来处理程序的正常控制流
- 不要随便将异常迎函数栈向上传递,能处理尽量处理
何时向上传播?
- 当你认为本异常应该由上层处理时,才向上传播
注意点
finally
语句块一定会执行吗?
不一定会,以下两种情况finally语句块不会执行
- 未执行到try语句块
- try语句块中有System.exit(0);
finally
语句块的执行顺序
首先看没有控制语句的情况:
public static void main(String[] args) { try { System.out.println("try block"); } finally { System.out.println("finally block"); }}复制代码
输出没有疑问: try block finally block
1、如果
try
中有控制语句(return
、break
、continue
),那finally
语句块是在控制转义语句之前执行还是之后执行?
private static String test1() { System.out.println("test1()"); return "return";}private static String test() { try { System.out.println("try block"); return test1(); } finally { System.out.println("finally block"); }}public static void main(String[] args) { System.out.println(test());}复制代码
输出: try block test1() finally block return
所以说,如果try
中有控制语句(return
、break
、continue
),那finally
语句块是在控制转义语句之前执行
2、如果
catch
语句中有控制语句(return
、break
、continue
),那finally
语句块是在控制转义语句之前执行还是之后执行?
private static String test1() { System.out.println("test1()"); return "return";}private static String test() { try { System.out.println("try block"); System.out.println(1 / 0); return test1(); } catch (Exception e) { System.out.println("catch block"); return test1(); } finally { System.out.println("finally block"); }}public static void main(String[] args) { System.out.println(test());}复制代码
输出: try block catch block test1() finally block return
所以说,如果catch
语句中有控制语句(return
、break
、continue
),那finally
语句块是在控制转义语句之前执行
finally
里的变量
public static int test() { int i = 0; try { return i; } finally { i++; }}public static void main(String[] args) { System.out.println(test());}复制代码
输出: 0
咦?很奇怪,为什么是0,而不是1呢?
通过反编译生成的class,我们就能知道原因了
int i = 0;try { return i;} finally { int iTemp = i++;}复制代码
原来,i++后只是赋值给了一个新的局部变量
,i本身并没有变,这一点和函数的形参一样,如果传的是引用类型
的,那么值会变,如果传的不是引用类型,那么值是不会改变的,改变的也只是局部变量。