Java中try...catch使用经验总结

04月18日 收藏 0 评论 0 java开发

Java中try...catch使用经验总结

转载声明:文章来源https://zhuanlan.zhihu.com/p/332320734

1,概要

对于一个合格的Java程序员来说,在自己的代码逻辑中使用try...catch来进行异常处理是非常常见且必要的事情,因为它让你的程序更加健壮稳定。但是如何合理规范的使用它却是很多初级程序员,甚至很多工作多年的老程序员并不十分清楚的。今天我就结合自己多年在Java编码中的经验来谈谈自己的看法,希望对各位童鞋有所帮助。

2,异常分类

首先,我们要清楚为什么要写try...catch,根本原因在于程序会出现可能的问题,而这个问题是指:阻止当前方法或者作用域继续执行的问题(此句引用《Java编程思想第四版》对Java异常的定义),它会阻止你的程序沿着你预先编写的逻辑继续往下运行。所有的这种可能出现的问题在Java中统一叫做Throwable。而Throwable又可以归为2大类: Error 和Exception,具体如下图所示:

异常分类总览

3,什么是Error

其中,Error也叫错误,这部分是程序员无法处理的,很多情况下try...catch了也没有用,程序依然会crash退出,因为这部分属于Java虚拟机异常,跟你代码逻辑无关(其实还是有关的,可能是你代码设计有问题,比如程序中有很深的递归调用导致StackOverFlowError;数据处理时用有限的内存处理了太多的数据导致OutOfMemoryError等),这部分出现的异常最大的特点是:异常出现时,程序员无法用常规的try...catch或者throws方式进行处理,因为无法处理。而对于这部分的问题,程序员只能在程序设计、运行环境以及运行参数上去尽量规避。

4,什么是Exception

而对于程序员来说,能施展你对程序异常处理才华的部分,就只能是程序的Exception部分了,而对于这部分又分为运行时异常(RuntimeException)和非运行时异常(非RuntimeException)。其中,RuntimeException又叫非检查异常,非RuntimeException又叫检查异常。如下图所示:

Exception种类划分

4.1 检查性异常

表示在正常的程序运行期间可能发生的预期问题,该部分异常是程序要求你必须处理的否则编译无法通过。比如当你用程序尝试跟外部IO设备进行通信时,可能会发生的IO异常现象,该部分异常的发生是不可避免的,由外部因素决定,程序本身无法杜绝。相信大家在编码时候一定遇到这种情况,比如我引用了个第三方的库或者jar包,然后调用其中的api时候发现,咦... 明明我是按照要求调用的啊,怎么编辑器飘红了啊,打开提示发现,哦... 原来有Exception没有处理,这个时候你可以选择用try...catch进行处理或者用throws把该异常往上抛(至于用那种方式,别急,后文会介绍),那么这种情况下出现的异常就叫做检查性异常,也就是你在代码中不得不处理的异常

4.2 非检查性异常

表示不需要进行强制处理的异常,只会发生在程序运行时,该部分异常的产生多半是因为数据的缘故导致,之所以JVM没有强制性要求程序员去处理,因为该部分的异常是程序员可以杜绝的(可预先进行条件判断处理,增加代码的健壮性)。比如常见的NullPointerException、ClassCastException,因为是非检查异常,即便程序员不做任何处理程序也是可以通过编译的。

5,如何规范使用try...catch

对于以上提到的各种异常情况(Exception),该如何处理呢。应该秉承以下几个原则:

对检查性异常而言:

①如果明确知道如何处理异常,比如捕获异常后,执行回滚机制,重试机制等,可进行try...catch操作;
②如果不清楚当前异常如何处理,则直接进行throws,把异常交给调用层处理。一般不建议把异常try...catch之后只是仅仅把方法的调用栈打印出来,这样不能叫做真正意义的异常处理;
③如果要try的代码块,与后续要执行的代码逻辑是解耦的(即该部分调用是否有异常跟后面要运行的代码逻辑没有关系),为了避免该部分因为运行异常导致的程序crash退出,可将该部分进行try...catch;

对于非检查性异常而言:

尽量使用条件判断来代替可能的try...catch操作,比如如下的try...catch逻辑:

public void fun3(){
Object obj = fun1();
try {
obj.fun2();
} catch (NullPointerException e) {
//处理逻辑
}
}

可以优化为:

public void fun3(){
Object obj = fun1();
if (null == obj){
//处理逻辑
}
else{
obj.fun2();
}
}

②如果不清楚当前写的代码逻辑是否会有运行时异常抛出,则不要盲目的进行try...catch或者throws,在代码进行测试时遇到了可能的异常后,再针对具体的异常进行异常处理;

③在对可能出现异常的代码进行try...catch时,尽可能避免将无关代码加入到try...catch体内,比如:

public void fun3(){
try {
int a = 10;//不会抛出异常
String b = fun2();//不会抛出异常
Object obj = fun1();
} catch (Exception e) {
//处理逻辑
}
}

要改为:

public void fun3(){
int a = 10;//不会抛出异常
String b = fun2();//不会抛出异常
try {
Object obj = fun1();
} catch (Exception e) {
//处理逻辑
}
}

④不要滥用try...catch,一定只对确定的需要进行异常捕获的代码块进行try...catch,try...catch体中的代码量越少越好,尤其不要搞嵌套的try...catch;

6,try...catch的优缺点总结

凡事有利就有弊,try...catch在异常处理方面给程序员带来的便捷(将正常情况下的程序处理逻辑和发生异常后的程序处理逻辑分开)的同时,也同样会带来一些不便,对于try...catch的优缺点,总结如下:

优点
①对可能出现的预期的异常,可将程序恢复到某个已知的稳定点上;
②对可预见性的异常,可进行重试机制或者实施替代方案进行业务补救措施,避免业务损失;
③避免了因为一些无关紧要的异常(不影响程序的执行结果),导致的程序直接crash退出;

缺点
①让代码的可读性变差,尤其是频繁大量的try...catch使用情况下;
②try...catch体内的代码块,编译器在运行时很难进行优化处理,某种程度上削弱了代码执行效率;
③异常一旦发生,对其进行捕获的过程是非常消耗系统资源的,会降低程序的执行效率(因此,能用条件判断解决的就一定不要用try...catch);

以上,就是我对try...catch使用经验的总结,希望对你有所帮助。如果有任何问题,欢迎大家批评指正,多多交流!

C 0条回复 评论

帖子还没人回复快来抢沙发