引言
java中提供了丰富的异常处理方式。
每个人的代码中都少不了try catch, 但是如何使用异常处理,才会最大化程序的健壮性和可维护性呢?
用好异常机制的前提是充分理解以下两个问题:
- 理解exception和error的差别
- 理解运行时异常和其他异常的差别
详见文档:Java异常汇总
原则:
- 不要捕获类似Exception这类的通用异常,而是应该捕获特定异常
try{
array[i++].toString();
String b = new String(c);
}catch(Throwable e){
}
主要问题:
- 可读性差,对比:
try{
array[i++];
}catch(ArrayIndexOutOfBoundException e){
logger.error..
}
- 一些我们希望能抛出来的RuntimeException会被吞掉。
- OutOfMemoryError等异常也不能被正常处理
- try-catch代码段要尽可能少,不要一整段代码,包在一个try-catch里。
主要问题:
- try-catch在执行时有额外的jvm开销,所以try-catch不能滥用,否则程序整体性能会受影响。
- 千万不要生吞异常
反例如下:
try{
function();
}catch(ArrayIndexOutOfBoundException e){
//1. do nothing
//2. e.printStackTrace()
}
主要问题:
- 没有抛出异常,也没有记录异常。生产环境中遇到这种情况完全没法诊断。
- e.printStackTrace()会输出到标准输出流里。在分布式等复杂架构的线上系统中,无法准确定位标准输出流文件。正常的方式,应该是输出到统一的产品日志中。
- 异常只用来处理异常情况,他们永远不应该用于正常的控制流。比如:
在下例中,异常(ArrayIndexOutOfBoundException)被用作数组遍历完成的条件,而非异常情况处理。
try{
while(true){
array[i++].climb();
}
}catch(ArrayIndexOutOfBoundException e){
}
主要问题:
- 可读性不好,对比:
for(Mountain m:array){
m.climb();
}
-
异常被吞: catch到ArrayIndexOutOfBoundException之后没有输出到产品日志中,不便于线上问题诊断。
-
array不一定会被完全遍历: climb()方法里若抛出ArrayIndexOutOfBoundException。
-
现代JVM中对正常的数组遍历是有优化的,不使用正常的遍历比如for,foreach等,而是使用try catch的方式来实现遍历,无法享受jvm的优化。
-
不要在try block中处理返回值,,即不要有return。 同时也不要在try block里包含continue, break,因为这两个语句也有可能将控制权转给finally.
-
函数返回值为对象引用时,要注意finally代码块中,对该返回对象的成员变量如果有改动,该改动也会作用到返回值上。
比如:
SomeClass result = new SomeClass();
try{
return result;
}catch(CertainException e){
//logger.error...
}finally{
result.setSomeMember(323);
}
这种情况下返回的对象的SomeMember属性会变化
网友评论