Java中try...catch使用
本文参考自https://zhuanlan.zhihu.com/p/332320734
概要
对于一个合格的Java程序员来说,在自己的代码逻辑中使用try…catch来进行异常处理是非常常见且必要的事情,因为它让你的程序更加健壮稳定。
异常分类
首先,我们要清楚为什么要写try…catch,根本原因在于程序会出现可能的问题,而这个问题是指:阻止当前方法或者作用域继续执行的问题,它会阻止你的程序沿着你预先编写的逻辑继续往下运行。所有的这种可能出现的问题在Java中统一叫做Throwable。而Throwable又可以归为2大类: Error 和Exception,
Error
其中,Error也叫错误,这部分是程序员无法处理的,很多情况下try…catch了也没有用,程序依然会crash退出,因为这部分属于Java虚拟机异常,跟你代码逻辑无关(其实还是有关的,可能是你代码设计有问题,比如程序中有很深的递归调用导致StackOverFlowError;数据处理时用有限的内存处理了太多的数据导致OutOfMemoryError等),这部分出现的异常最大的特点是:异常出现时,程序员无法用常规的try…catch或者throws方式进行处理,因为无法处理。而对于这部分的问题,程序员只能在程序设计、运行环境以及运行参数上去尽量规避。
Exception
而对于程序员来说,能施展你对程序异常处理才华的部分,就只能是程序的Exception部分了,而对于这部分又分为运行时异常(RuntimeException)和非运行时异常(非RuntimeException)。其中,RuntimeException又叫非检查异常,非RuntimeException又叫检查异常。如下图所示:
检查型异常
表示在正常的程序运行期间可能发生的预期问题,该部分异常是程序要求你必须处理的,否则编译无法通过。比如当你用程序尝试跟外部IO设备进行通信时,可能会发生的IO异常现象,该部分异常的发生是不可避免的,由外部因素决定,程序本身无法杜绝。这种情况下出现的异常就叫做检查性异常,也就是你在代码中不得不处理的异常。
非检查性异常
表示不需要进行强制处理的异常,只会发生在程序运行时,该部分异常的产生多半是因为数据的缘故导致,之所以JVM没有强制性要求程序员去处理,因为该部分的异常是程序员可以杜绝的(可预先进行条件判断处理,增加代码的健壮性)。比如常见的NullPointerException、ClassCastException,因为是非检查异常,即便程序员不做任何处理程序也是可以通过编译的。
如何规范使用try…catch
对于以上提到的各种异常情况(Exception),该如何处理呢。应该秉承以下几个原则:
对检查性异常而言:
- 如果明确知道如何处理异常,比如捕获异常后,执行回滚机制,重试机制等,可进行try…catch操作;
- 如果不清楚当前异常如何处理,则直接进行throws,把异常交给调用层处理。一般不建议把异常try…catch之后只是仅仅把方法的调用栈打印出来,这样不能叫做真正意义的异常处理;
- 如果要try的代码块,与后续要执行的代码逻辑是解耦的(即该部分调用是否有异常跟后面要运行的代码逻辑没有关系),为了避免该部分因为运行异常导致的程序crash退出,可将该部分进行try…catch;
对于非检查性异常而言:
- 尽量使用条件判断来代替可能的try…catch操作,比如如下的try…catch逻辑:
1 | public void fun3(){ |
可以优化为
1 | public void fun3(){ |
- 在对可能出现异常的代码进行try…catch时,尽可能避免将无关代码加入到try…catch体内,比如:
1 | public void fun3(){ |
应该为:
1 | public void fun3(){ |
- 如果不清楚当前写的代码逻辑是否会有运行时异常抛出,则不要盲目的进行try…catch或者throws,在代码进行测试时遇到了可能的异常后,再针对具体的异常进行异常处理;
- 不要滥用try…catch,一定只对确定的需要进行异常捕获的代码块进行try…catch,try…catch体中的代码量越少越好,尤其不要搞嵌套的try…catch;
try…catch的优缺点总结
凡事有利就有弊,try…catch在异常处理方面给程序员带来的便捷(将正常情况下的程序处理逻辑和发生异常后的程序处理逻辑分开)的同时,也同样会带来一些不便,对于try…catch的优缺点,总结如下:
优点:
- 对可能出现的预期的异常,可将程序恢复到某个已知的稳定点上;
- 对可预见性的异常,可进行重试机制或者实施替代方案进行业务补救措施,避免业务损失;
- 避免了因为一些无关紧要的异常(不影响程序的执行结果),导致的程序直接crash退出;
缺点:
- 让代码的可读性变差,尤其是频繁大量的try…catch使用情况下;
- try…catch体内的代码块,编译器在运行时很难进行优化处理,某种程度上削弱了代码执行效率;
- 异常一旦发生,对其进行捕获的过程是非常消耗系统资源的,会降低程序的执行效率(因此,能用条件判断解决的就一定不要用try…catch);