什么时候可以捕获RuntimeException


69

在最近的项目中,我建议在测试工具代码中捕获RuntimeException并将其记录下来。该代码处理来自数据库的一系列输入,并且我不希望由于任何一个输入(空值,非法参数等)失败而导致测试停止。不用说,我的建议引起了热烈的讨论。

捕获任何一种RuntimeException是否可以接受?如果是,那么可以捕获RuntimeExceptions的其他方案还有哪些?

Answers:


100

捕获RuntimeException此异常的原因与捕获任何异常的原因相同:您打算对其进行处理。也许您可以纠正导致异常的任何原因。也许您只是想重新抛出其他异常类型。

但是,捕获和忽略任何异常是非常糟糕的做法。


3
完全有道理,应该回到基础。很多时候,模式变得一成不变,以至于开发人员倾向于将它们当作“教条”。我一直被告知RuntimeExceptions是a)编程错误b)灾难性故障(无法从中恢复)的结果。在情况(a)中,您要确保在产品上线之前一切都已固定,并且“永远”不会发生。至于情况(b),用户应该看到更干净的消息对于捕获和处理非常有意义。现在我想知道为什么我们根本需要RuntimeExceptions,也许是另一个讨论的主题;-)
VDev

1
嘿,我认为将所有异常都设为运行时异常是更多原因。有很多程序员会捕获并忽略已检查的异常,只是为了使它们消失。
kdgregory,2009年

1
@LokiAstari没有抓住并重新抛出;由于相同的异常可能会出现两次,因此调试时会造成混乱。记录并显示异常消息是可以接受的,或者记录跟踪并重新抛出异常。或不记录并重新抛出。

35

除非您可以纠正RuntimeException,否则您不希望捕获它。

...仅从开发人员的角度来看是正确的...

您必须捕获所有异常,然后它们才能到达用户界面并让您的用户难过。这意味着在“最高级别”上,您想捕获进一步发生的所有事件。然后,您可以让用户知道问题所在,同时采取措施通知开发人员,例如发送警报邮件或其他任何内容。

基本上,它被认为是无法预见的数据/编程错误,因此,您希望改进软件的未来版本,同时牵手用户并以受控方式继续前进...


15

RuntimeException旨在用于程序员错误。因此,它永远不会被抓住。在某些情况下应为:

  1. 您正在调用来自第三方的代码,您无法控制他们何时抛出异常。我认为您应该根据具体情况进行此操作,并将第三方代码的用法包装在您自己的类中,以便可以传回非运行时异常。

  2. 您的程序无法崩溃,并且不会留下堆栈跟踪供用户查看。在这种情况下,它应该围绕main以及所有线程和事件处理代码。当此类异常发生时,程序可能也应该退出。

在您的特定情况下,我将不得不质疑为什么在测试中出现RuntimeExceptions-您应该修复它们而不是解决它们。

因此,您应该保证您的代码仅在想要退出程序时才抛出RuntimeExceptions。您只应在想记录RuntimeExceptions并退出时才捕获它。这符合RuntimeExceptions的意图。

您可以出于人们给出的其他一些原因来查看此讨论...尽管我个人在答案中还没有找到令人信服的理由。


1
或者3.您可以在中级问题上解决或解决该问题,然后再从堆栈树中逃脱
tar

7

几年前,我们编写了一个控制系统框架,Agent对象捕获了运行时异常,并在可能的情况下将其记录下来并继续。

是的,我们在框架代码中捕获了包括OutOfMemory在内的运行时异常(并强制执行了GC,这令人惊讶的是,即使泄漏非常严重的代码也能正常运行)。由于小数舍入错误,有时会出现Not-A-Number的问题,因此也可以解决。

因此,在框架/“不得退出”代码中,我认为这是合理的。当它起作用时,它非常酷。

该代码相当可靠,但是它运行硬件,并且硬件有时会给出一些棘手的答案。

它设计为一​​次可以运行几个月,而无需人工干预。在我们的测试中,它表现得非常出色。

作为错误恢复代码的一部分,它可以使用UPS在N分钟内关闭并在M分钟内打开的能力来重启整个建筑物。

有时,硬件故障需要重新上电:)

如果我还记得的话,在电源重启失败后的最后一招就是向其所有者发送电子邮件,说“我试图修复自己,但我不能解决;问题出在XYZ子系统上”,并包括一个提出支持的链接打电话给我们。

可悲的是,该项目在变得自我意识之前就被罐装了:)>


加一个提及“自我意识”的人……仅在1997
。– shrini1000 2014年

7

在我的代码中,我99%的异常都来自runtime_exception。

我捕获异常的原因是:

  • 捕获日志并修复问题。
  • 捕获日志并生成更具体的异常并抛出
  • 捕获日志并重新抛出
  • 捕获日志和终止操作(丢弃异常)
    • 用户/请求启动的操作失败。
      例如,HTTP请求处理程序。我宁愿请求的操作死掉,也不愿放弃服务。(尽管处理程序最好具有足够的意识以返回500个错误代码。)
    • 测试用例通过/失败,但有异常。
    • 所有异常不在主线程中。
      通常很难记录允许异常转义线程,但通常会导致程序终止(不展开堆栈)。

4

就个人而言,我总是被告知您要捕获所有RuntimeExceptions。但是,你也想要做的事有关的例外,如运行故障安全或者可能只是告知出现了错误的用户。

我从事的最后一个Java项目也采用了类似的方法,至少,我们会记录该异常,这样,如果用户致电抱怨某个错误,我们就可以准确地了解发生了什么并查看错误发生的位置。

编辑1:正如kdgregory所说,捕捉和忽略是两件事,通常,人们反对后者:-)


3

我们都知道检查异常和RuntimeExceptions是异常的两类。始终建议我们处理(尝试捕获或抛出)已检查的异常,因为不幸的是它们是编程条件,程序员不能单独执行任何操作。就像FileNotFoundException不是程序员将文件放置在用户驱动器上,如果程序实际上试图读取该文件1.txt,该文件应该f:\带有以下语句:

File f11 = new File("f:\\1.txt");
FileInputStream fos = new FileInputStream(f11);

如果找到该文件就可以了,但是在另一种情况下如果找不到该文件又会发生什么,则程序将崩溃,并出现用户0错误。在这种情况下,程序员没有做错任何事情。这可能是一个已检查的异常,必须捕获该异常才能使程序继续运行。

让我也解释一下第二种情况,在这种情况下概念RuntimeException将很清楚。考虑以下代码:

int a = {1,2,3,4,5};
System.out.println(a[9]);

这是不良的编码,会产生ArrayIndexOutOfBoundsException。这是一个示例RuntimeException。因此,程序员不应实际处理该异常,不要让该异常使程序崩溃,然后再修复逻辑。


3

RuntimeException当您要处理它时,您会抓住。也许您想将其作为其他异常重新抛出,或者将其记录到文件或数据库中,或者想要在返回类型中打开某些异常标志,等等。


1

当程序执行多个子任务时,您会捕获RuntimeExceptions(以任何语言:意外的异常/“所有”异常),并且有可能完成每个任务,而不是在出现第一个意外情况时停止,这很有意义。测试套件是执行此操作的好方法-您想知道所有测试中哪些失败了,而不仅仅是第一个测试。关键特征是每个测试都独立于其他所有测试-先前的测试是否不重要并不重要,因为顺序并不重要。

另一个常见的情况是服务器。您不希望仅因为一个请求的格式不符合您的预期而关闭。(除非最小,非常重要的是最小化状态不一致的可能性。)

在任何这些情况下,适当的操作是记录/报告异常并继续执行剩余的任务。

一个模糊的概括可以归结为任何异常:只有捕获有明智的事情要做的情况下,“适当地捕获”异常:程序应如何继续


0

如果可以合理地期望客户端从异常中恢复,请使其成为已检查的异常。

如果客户端无法采取任何措施来从异常中恢复,请将其设置为未经检查的异常。

这是底线准则。

来自Java Docs。请阅读以下未经检查的例外情况-争议

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.