异常处理遇到过的那些坑

1,765 阅读4分钟

今年有个目标之一就是提升团队代码的质量,所以时常会思索如何把这件事做到更好,不想教条主义,也不想搞出一个代码规范,强制团队照着做,落地的效果不好,反而把大家的积极性给弄没了。所以我的原则是,我们一起看看什么事是我们不能做的,排除掉,剩下的就是我们可以做的,同时真正搞清楚问题在哪里,而不是简单的模仿。从我个人的经验看,代码优化中最重要的一点就是对异常情况的处理。今天,我就借这个话题,谈谈如何来优化我们的代码。


坑1:捕捉异常不做处理


如下段代码所示,不知道各位在自家的代码中见过多少,我是期望大家不要遇见。且不说printStackTrace()这样的代码就不应该出线在正式的上线代码中,不做处理本身这会导致业务的潜在问题被隐藏了,所以这个坑是我认为异常处理中最糟糕的一点。


try

{

....

}

catch(Exception ex)
{

ex.printStackTrace();

System.out.println(XXX);

}



对于异常的捕捉处理,遵循以下的流程:

  1. 处理该异常,执行具体的逻辑处理,加上必要的系统日志记录 (log4j,logcat ...)。

  2. 涉及其他系统或者上一级系统,需要转换成对应的消息通知相关系统。上一级是前端,需要转换成前端可以“读懂”的错误提示。

  3. 无法处理该异常或者该异常需要上一级统一处理,Throw out该异常。


坑2:不处理资源释放


还是见代码说话,如果append出错,那么IO流就不会被关掉,那么最终就会导致整个程序因为溢出崩掉。


FileWriter fileWriter = null;

try

{

fileWriter = new FileWriter("");

fileWriter.append(item.toString());

fileWriter.close();

}

catch (IOException e)

{

...

}

在使用文件、IO流、数据库连接等不会自动释放的资源时,应该在使用完毕后马上将其关闭。关闭资源的代码try...catch...finally的finally内执行,否则就可能因为Exception的原因造成资源无法释放。


坑3:对异常不进行分类处理


代码中,最容易看到的一种情况就是设定catch的异常类型是Exception, 并且只有一套处理逻辑, 如下:

try{

...

}

catch (Exception e){

...

}


这里的问题主要有以下两点:


1. catch的不同Exception,可能需要执行不同的处理逻辑,一个catch要同时处理所有逻辑就很难实现。

2. 由于是捕捉的基类Exception, 那么RuntimeException也会被捕捉到,如果稍微不注意的话,RuntimeException最终没有任何实际处理,代码中的真正错误被掩盖掉了。


所以,正确的做法应该是按照具体的异常进行分类处理, 例如:

try{

...

}

catch (FileNotFoundException e){

// alert that the specified file

// does not exist

}

catch (EOFException e){

// alert that the end of the file

// was reached

}

catch (ObjectStreamException e){

// alert that the file is corrupted

}

catch (IOException e){

// alert that some other I/O

// error occurred

}


坑4:将大段代码放进一个Try-Catch中

  有时可以看到,一些代码的作者恨不得把整个函数里的实现代码都放入单个try中,原因就在于为了图省事,不愿花时间分析一大块代码中哪几行代码会抛出什么异常、异常的具体类型是什么,应该如何处理。这样的做法导致异常发生后,后续调试找问题更麻烦,一大段代码中有太多的地方可能抛出Exception。这样的做法导致,很难去统计和判断要catch哪一些类型的Exception, 只能写一个粗糙的Exception, 又掉进我们说的第3个坑里。


一点总结


在和大家一起分析了上面的异常坑后,如果未来我们想避免踩进一个异常坑,编写异常代码可以遵循以下三个点:


1. 出了什么错?

2. 在哪出的错?

3. 为什么出错?


扫描二维码或手动搜索微信公众号【架构栈】: ForestNotes

欢迎转载,带上以下二维码即可