一次对Java异常机制的理解
近期有一个对接三方接口的任务,在这个过程中用到了许多 try-catch 处理,发现自己对异常处理是一知半解,浅浅研究了一下,记录一下,也帮助小伙伴如何正确使用 try-catch 达到预期的结果。
写在前面
java
的异常处理机制,用得好,可以达到预期的效果,用得不好,反而会降低JVM
的性能
try-catch
代码段会产生额外的性能开销java
每实例化一个Exception
,都会对当时的栈进行快照,这是一个相对比较重的操作。
所以结论是:能不用则不用,如要用,尽量使 try 块的代码尽可能的少
1、循环中发生异常,导致循环中断
我现在有一个任务,需要循环去处理,代码如下:
public static void main(String[] args) throws Exception {
try {
// 处理任务
doProcess();
} catch (RuntimeException e) {
e.printStackTrace();
}
}
public static void doProcess() {
for (int i = 0; i < 30; i++) {
if (i % 10 == 0) {
throw new RuntimeException("Invalid number");
} else {
System.out.println(i);
}
}
}
我的预期是:当 i = 0,10,20 的时候抛出异常,其余情况打印 i 的值
实际结果:程序直接抛出异常就结束了
后来查了相关资料,发生异常的时候,JVM
会把异常往上抛,doProcess
方法不能处理这个异常,就抛到了 main
方法中,刚好 main
方法能够处理,但是处理完之后,当前的栈帧已经来到了 main线程
,也就是说,当异常抛出了 doProcess
方法之后,相当于这个方法已经执行完了。
后续经过改造,来到了version 2.0
:
public static void main(String[] args) throws Exception {
// 处理任务
doProcess();
}
public static void doProcess() {
try {
for (int i = 0; i < 100; i++) {
if (i % 10 == 0) {
throw new RuntimeException("Invalid number");
} else {
System.out.println(i);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
我的预期是:当 i = 0,10,20 的时候抛出异常,其余情况打印 i 的值
实际结果:程序直接抛出异常就结束了
经过分析,发生异常时,JVM
还是会把异常往上抛,被 for循环外
的 try 块
捕获了,但是为什么还是没能满足我们的预期,理由还是同上,在循环中发生异常,循环中无法捕获这个异常时,就会继续往上抛,一旦抛出了循环外,标志循环也结束了。
继续改造 version 3.0
public static void main(String[] args) throws Exception {
// 处理任务
doProcess();
}
public static void doProcess() {
for (int i = 0; i < 100; i++) {
try {
if (i % 10 == 0) {
throw new RuntimeException("Invalid number");
} else {
System.out.println(i);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
这次程序能满足我的预期了,在循环中发生异常,但是在循环中被捕获了,并没有跳出循环,所以循环还在继续。
通过这次对异常处理的思考,一定要尽可能小的去使用 try-catch
,一是能保证代码的正确性,二是能保证jvm的性能。