为什么捕获RuntimeException不被认为是良好的编程实践?

16
为什么使用 catch(Throwable exc) {} 来捕获 RuntimeException 不被认为是良好的编程实践? 处理 RuntimeException 的正确方式是什么?
此外,为什么 catch(Exception exc) {} 不能捕获 RuntimeException? 这种行为是如何实现的?

4
那个 catch 可以捕获 RuntimeException - Sotirios Delimanolis
2
因为未经检查的异常通常是可以通过使用“if”语句执行简单检查来避免的异常。例如,可以通过if(myObject != null)避免NullPointerException。此外,iftry-catch更快。只有在真正需要时才使用try-catch - BackSlash
4
我不赞同捕获RuntimeException是一种不好的做法。但是,捕获然后_忽略_错误......那就不好了。 - Tony Ennis
3个回答

28
通常,RuntimeException 表示编程错误(在这种情况下,您无法“处理”它,因为如果您知道要避免错误,那么就不会出现错误)。
捕获任何这些一般异常(包括 Throwable )都是不好的,因为这意味着你声称你理解每个可能出错的情况,并且你可以继续即使发生错误。有时候,在堆栈的顶层(例如在 Web 服务器中),捕获 Exception(但通常不是 Throwable )是适当的,因为通常针对于一个单独的请求所出现的问题,您通常希望保持服务器运行并响应进一步的请求。我通常不会捕获 Throwable ,因为其中包括通常用于指示真正灾难性错误的 Error 子类,这通常最好通过终止进程来“处理”。
从根本上讲,当出现错误时,您需要非常谨慎地继续执行特定任务,因为否则,您可能会在关于世界状态的错误假设前进,并使事情更加糟糕。在大多数情况下(不是全部),简单地放弃一个请求比试图在神秘的失败情况下继续进行更好。(但这非常依赖于上下文 - 例如在尝试获取一些辅助信息时,您可能不关心出了什么问题。)
至于捕获 Exception 而不是捕获 RuntimeException - 这根本不是真的。唯一奇怪的事情是 RuntimeException(及其子类)是未检查的异常,而 Exception 和所有其他 Exception 子类都是已检查的异常。

1
嗨,你能否详细说明一下检查异常和非检查异常的行为差异? - SPS
@SumitPalSingh:已经有很多好的信息可供参考了。阅读Java教程:http://docs.oracle.com/javase/tutorial/essential/exceptions/index.html - Jon Skeet
通过让 Error 实例冒泡,我们如何知道哪个组件会捕获它们?这个或那些组件将如何记录这些错误?当程序由于错误而崩溃时,我们如何知道发生了什么?有些错误可能很难复现。 - Stephan
@Stephan:通常在顶层会有某些东西记录错误,然后进程终止...此时您将拥有堆栈跟踪。具体细节取决于应用程序。(例如,对于控制台应用程序,它会自动发生,只需记录到stderr即可)。 - Jon Skeet

6
这归结于实际存在的不同类型的异常。
已检查异常(即扩展Exception的异常类)通常是您可以从中恢复的错误。
未检查异常(即明确扩展RuntimeException的异常类)指示预期行为或程序状态中的错误。当您取消引用对象时,如果对象的状态不为null,则不会出现NullPointerException,当然。
无论是捕获Exception还是Throwable(更糟糕),都不能一概而论,因为您假定可以从任何异常行为中恢复。有些情况下,您不应该或实际上无法(例如catch(Throwable t)的OutOfMemoryError)。此外,捕获运行时异常表示代码存在问题;这意味着您正在掩盖编码错误。
明确要捕获的内容。
另外:是的,catch Exception也会捕获RuntimeException,因为Exception是RuntimeException的超类。同样,Throwable将捕获Exception和Error,这就是为什么编写catch(Throwable t)更糟糕的原因。

“明确你要捕获的内容。”为什么?我认为这不是一个好的编程建议。如果您正在建模一个类,并且希望它永远不会向上传播异常,则捕获所有“Exceptions”就可以了。(我同意捕获Throwable不是一个好主意)。 - frankelot
通过让“错误”实例上升,我们如何知道哪个组件会捕获它们?这个或那些组件将如何记录这些错误?一旦程序因错误而崩溃,我们如何知道发生了什么?有些错误可能很难复现。 - Stephan
@Stephan:你没有足够的内存来捕获 OutOfMemoryError,那么谁在乎尝试捕获它的是什么? - Makoto

5

Throwable是所有Exception(已检查和未检查的RuntimeException)和error的超级类。

java.lang.Object
     java.lang.Throwable
          java.lang.Exception
               java.lang.RuntimeException
          java.lang.Error

理想情况下,捕获错误并不是一个好的实践。
由于RuntimeException扩展了Exception,因此它可以捕获所有RuntimeException

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接