捕获已检查的异常后重新引发运行时异常

2022-09-02 12:34:15

在 Java 中,观察到有一个约定,即在处理 .RuntimeExceptionChecked Exception

这种方式既有好的后果,也有坏的后果。当编译器强制通过 a 处理某些内容时,开发人员可以通过捕获它并将其重新作为 .Checked ExceptionRuntimeException

有人可以解释一下这种情况是否可以被视为一种好的做法吗?如果是这样,这种方法是否不那么容易出错,还是会使代码库不稳定?


答案 1

实际上,正是在处理已检查的异常方面的无能尝试导致了不稳定的代码库。通常,您将拥有以下内容:

try {
   //stuff
} catch (IOException e) {
   log.error("Failed to do stuff", e);
   throw e;
}

然后下一步,你将不得不再次处理它,通常记录它并弄乱日志文件。如果你不重新抛出,情况会更糟

try {
   // do stuff
} catch (IOException e) {
  return null;
}

现在调用代码不知道出了什么问题,更不用说出了什么问题了。与这些尝试相比,这实际上完全完成了应用程序逻辑所需的内容:

try {
  // do stuff
} catch (IOException e) {
  throw new RuntimeException(e);
}

现在,异常可以自由地向上传播调用堆栈,直到它到达明确定义的异常屏障,其中它:

  1. 中止当前工作单位;
  2. 记录在单个统一位置。

简而言之,要决定是捕获并处理还是捕获并返回,只需问自己以下问题:

此异常的发生是否必须中止当前的工作单元?

  • 如果:重新抛出未经检查的异常;
  • 如果不是:在 catch-block 中提供有意义的恢复代码。(否,日志记录不是恢复)。

根据多年的实际经验,我可以告诉您,所有可能的检查异常中,超过90%属于“中止”类型,无需在发生地点进行处理。

针对已检查异常的语言功能的参数

今天,检查的异常被广泛认为是语言设计中失败的实验,简而言之,这是关键论点:

API 创建者不能决定其在客户端代码中异常的语义。

Java的理由是,异常可以分为

  1. 由编程错误引起的异常(未选中);
  2. 由于程序员无法控制的情况而导致的异常(已选中)。

虽然这种划分在某种程度上可能是真实的,但它只能从客户端代码的角度来定义。更重要的是,这在实践中并不是一个非常相关的划分:真正重要的是在什么时候必须处理例外。如果要延迟处理,则在异常屏障处,检查异常不会获得任何好处。如果及早处理,则只有有时检查异常会带来轻微的收益。

实践已经证实,检查异常带来的任何收益都与对现实生活中项目造成的实际损害相形见绌,正如每个Java专业人员所见证的那样。Eclipse和其他IDE也是罪魁祸首,建议没有经验的开发人员将代码包装在try-catch中,然后想知道在catch-block中写什么。

每当你遇到一种方法时,你就发现了另一个活生生的证据,证明检查异常的缺陷。throws Exception


答案 2

检查异常的想法是“仅限Java” - 据我所知,Java之后没有语言采用这个想法。

有太多检查的异常被捕获...并默默地忽略了。

如果你看看Scala,他们也放弃了它 - 它只是为了Java兼容性。

在 Oracle 网站上的本教程中,您将找到以下定义:

如果可以合理地期望客户机从异常中恢复,请使其成为已检查的异常。
如果客户机无法执行任何操作来从异常中恢复,请将其设置为未选中的异常。

这个概念在Scala中也被采用,并且工作正常。

从技术上讲,您的提案是有效的。无论哪种方式都需要进行纪律和代码审查。


推荐