异常处理的两个基本原则

先来看一段代码:

try {
  // do something
  Thread.sleep(1000L);
} catch (Exception e) {
  // ignore it
}

代码虽短,但已经违反了异常处理的两个基本原则。

第一,尽量不要捕获类似Exception这样的通用异常,而是应该捕获特定异常。在这段代码中Thread.sleep()会抛出的InterruptedException。

在日常的开发合作中,我们读代码的机会往往会超过写代码,软件工程是门协作的艺术。所以我们有义务让自己的代码能够直观地体现出尽量多的信息。在这段代码中只是泛泛地使用了Exception,隐藏了我们的目的。

另外,我们也要保证程序不会捕获到我们不希望捕获的异常。比如一些非检查型异常(RuntimeException的子类,是否还记得“Java你需要知道(1)”?),此时你可能更希望将其扩散,而非捕获。

进一步讲,除非你已经深思熟虑,否则不要捕获Throwable或者Error,你确定你能够处理OutOfMemoryError这样的异常么?

第二,不要生吞异常。这是异常处理中要特别注意的事情,因为很可能会导致非常难以诊断的诡异情况。

生吞异常,往往是基于假设这段代码可能不会发生,或者感觉忽略异常时无所谓的,但是千万不要在产品代码做这种假设!如果我们不把异常抛出来,或者也没有输出到日志(Logger),程序可能在后续代码以不可控的方式结束。没人可以轻易判断是哪里抛出了异常,以及是什么原因产生了异常。

再来看看下面这段代码:

try {
  // do something
} catch (IOException e) {
  e.printStackTrace();
}

上面这段代码如果出现在实验代码中,没有任何问题,但如果出现产品代码中,通常都不允许这样处理。这是为什么呢?(不妨先思考一下再往下看)

printStackTrace()的文档开头有这样一段描述:“Prints this throwable and its backtrace to the standard error stream”。问题就在这里,在稍微复杂一点的生产系统中,标准出错(STERR)不是个合适的输出选项,因为你很难判断到底输出到哪里去了。尤其是对于分布式系统,如果发生异常,但是因此无法找到堆栈轨迹,这纯属为诊断设置障碍。所以,最好的选择就是输出到产品日志中。

猜你喜欢

转载自blog.csdn.net/qweqwruio/article/details/81329542