捕获Checked Exceptions后重新抛出RuntimeExceptions

时间:2013-05-28 14:10:12

标签: java exception exception-handling

在Java中,观察到在处理RuntimeException之后有一个重新抛出Checked Exception的惯例。

这种方式有好的和坏的后果。当编译器强制通过Checked Exception处理某些内容时,开发人员可以通过捕获它并将其作为RuntimeException重新抛出来摆脱它。

有人可以解释一下这种情况是否可以被认为是一种好的做法?如果是这样,这种方法是否会减少错误,还是会使代码库不稳定?

5 个答案:

答案 0 :(得分:16)

实际上,处理检查异常导致代码库不稳定是无能的尝试。通常,你会有这个:

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. 记录在一个统一的地方。
  3. 简而言之,要决定是抓捕还是抓住并重新抛出,只要问自己这个问题:

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

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

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

    针对已检查异常的语言功能的争论

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

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

    Java的推理是异常可以分为

    1. 编程错误导致的异常(未选中);
    2. 由程序员控制之外的情况引起的异常(选中)。
    3. 虽然这种划分在某种程度上可能是真实的,但它只能从客户端代码的角度来定义。更重要的是,它在实践中并不是一个非常相关的部门:真正重要的是在何时必须处理异常。如果要处理延迟,则在异常屏障处,检查异常不会获得任何结果。如果提前处理,那么只有有时从已检查的异常中获得温和的收益。

      实践已经证实,通过对现实生活项目造成的实际损害相比,由经过检查的例外提供的任何收益都相形见绌,正如每位Java专业人员所见证的那样。 Eclipse和其他IDE也应该受到指责,建议没有经验的开发人员将代码包装在try-catch中,然后想知道在catch块中写什么。

      每当遇到throws Exception的方法时,您已经找到了另一种生活证据,证明了检查异常的不足。

答案 1 :(得分:2)

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

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

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

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

  

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

Scala也采用了这个概念,它运行良好。

从技术上讲,您的提案有效。无论如何都需要纪律和代码审查。

答案 2 :(得分:1)

在这种情况下,术语“可以摆脱它”并不完全正确。这摆脱了例外:

 try {

    } catch (Exception e){
        e.printStacktrace();
    } 

这是try-catch使用中最常见的不良做法。您正在捕获异常,然后打印它。在这种情况下,catch块捕获异常并打印它,而程序在catch块后继续好像什么也没发生

当您决定捕获块而不是抛出异常时,您必须能够管理异常。有时,例外情况无法管理,而且必须抛出

这是你应该记住的事情:

  

如果客户端可以采取一些备用操作来从中恢复   异常,使其成为检查异常。如果客户端做不到   任何有用的东西,然后取消选中该异常。我的意思是,有用   采取措施从异常中恢复,而不仅仅是记录   异常。

如果你不打算做一些有用的事情,那就不要抓住异常了。 将其作为RuntimeException重新抛出有一个原因:如前所述,程序无法继续,因为没有发生任何事情。这样,一个好的做法是:

try {

    } catch (Exception e){
        //try to do something useful  
       throw new RuntimeException(e); 
    } 

这意味着:您刚刚捕获了一个异常(如SQLException),无法在不停止和重置线程的情况下从中恢复。你抓住它,你试图在两者之间做一些事情(比如重新设置一些东西,关闭打开的套接字等等),然后抛出一个RuntimeException()

RuntimeException将挂起整个线程,如果没有发生任何事情,则避免程序继续作为此外,您可以管理另一个异常,而无需打印它。

答案 3 :(得分:0)

取决于具体情况,可能会也可能不会,但可能不是。

根据经验,RuntimeExceptions只应用于表示编程错误(例如,包括IllegalArgumentException和IllegalStateException)。它们不必被检查异常,因为您通常认为您的程序是正确的,除非另有证明,并且您无法以有意义的方式处理这些异常(您必须发布该程序的更新版本)。

运行时异常的另一个有效用途是当您使用将为您捕获和处理异常的框架时。在这种情况下,当你不打算处理它时,必须在每个方法中声明异常只会很麻烦。

所以一般来说,我会说重新抛出一个已检查的异常作为运行时异常是非常糟糕的做法,除非你有一个能够正确处理它的框架。

答案 4 :(得分:0)

一般规则是:当调用者可以在得到通知时进行某种恢复时,抛出一个已检查的异常。否则,抛出未经检查的异常。

此规则适用于首次抛出异常时。

但是这也适用于捕获异常并且想知道是否抛出已检查或未检查的异常。因此,没有约定在捕获已检查的一个之后抛出RunTimeException。它是根据具体情况决定的。

一个小提示:如果你只是在捕获一个之后重新抛出一个已检查的异常并且什么也不做,那么大多数时候只是不捕获异常并将其添加到方法抛出的异常中是正常的。