1、 java异常的主要回答了三个问题:
- what:异常类型回答了什么被抛出;
- where:异常堆栈跟踪回答了在哪被抛出;
- why:异常信息回答了为什么被抛出;
2、 java 异常分类
- Error:程序无法处理的异常,编译器不做检查。一般指和jvm相关的问题,如系统崩溃,虚拟机错误,内存空间不足,方法栈溢出等;
- Exception:程序可以处理的异常,捕获后可能恢复。
- 总结:前者是无法处理的错误,后者是程序可以处理的异常。
3、Exception
由上图所示,Exception可以分为RunTimeException和 非RunTimeException。
- RunTimeException:不可预知,程序应当自行避免。比如空指针异常,数组下标越界异常等。这类异常程序无法预知,但编写程序时可以进行避免,比如空指针异常,完全可以先进行非空判断在进行后续操作。
- 非RunTimeException:可以预知,编译器可以校验的异常。比如IOException等,我们要么要try。。。catch。。。,要么就抛给上一层处理,否则是无法编译通过的。
常见非RunTimeException:
不相信的同学可以试一下:throw new Error();
throw new RuntimeException();
throw new Exception();
只有第三个才会被编译器抓住,需要进行处理。
4、常见错误和异常
- 常见Error:
NoClassDefFoundError --找不到class定义的错误
StackOverflowError --深递归导致栈被耗尽而抛出的错误
OutOfMemoryError --内存溢出错误
- 常见RunTimeException:
NullPointerException --空指针异常
ClassCastException --类型强制转换异常
IllegalArgumentException --非法参数异常
IndexOutOfBoundsException --下标越界异常
NumberFormatException -- 数字格式异常
- 常见非RunTimeException:
ClassNotFoundException --找不到class定义的异常
IOException --IO操作异常
。。。。。。
5、 java异常处理机制
- 抛出异常:创建异常对象,交由运行时系统处理
异常对象包含了异常类型,异常出现时程序状态等异常信息。运行时系统负责寻找处置异常的代码并执行。
- 捕获异常:寻找合适的异常处理器处理异常,否则终止运行
6、 java异常处理原则
- 具体明确:抛出的异常应该能通过异常类名和messge错误信息尽可能的说明异常的类型以及异常产生的原因,所以一般不要直接throw exception,这种太抽象,不利于分析;
- 提早抛出:尽可能早的抛出异常,便于精确定位;
- 延迟捕获:异常的捕获和处理应该尽可能延迟,以便掌握更多的异常信息。
7、异常的执行
如下代码:
(1)有多个catch模块时,俺顺序匹配catch块,当能匹配到多个的时候,只执行第一个里面的代码;
(2)finally代码块会在其他模块的return之前执行(具体可以debug看看执行顺序哈)
比如上诉代码的运行结果:
最终结果为3不是1,验证了第(2)条。
8 Exception性能
如下代码:
执行后的结果
说明try-catch的性能和if-else比,是要低很多的。
java异常处理消耗性能的地方
- try-catch块影响jvm的优化;
- 异常对象实例需要保存栈快照等信息,开销大。所以try最后只放必要的代码,不要搞一个大的try-catch。
讲了这么多,那平时一般要怎么处理系统异常呢?
请见我的另一篇博客:springboot 统一异常处理(包含统一数据校验)