119

在什么情况下应该抓住java.lang.Error一个应用程序?

4

16 回答 16

104

一般来说,从不。

但是,有时您需要捕获特定的错误。

如果您正在编写类似于框架的代码(加载第 3 方类),那么捕获LinkageError(未找到类定义、不满意的链接、不兼容的类更改)可能是明智之举。

我还看到一些愚蠢的 3rd-party 代码抛出 的子类Error,所以你也必须处理这些。

顺便说一句,我不确定是否无法从OutOfMemoryError.

于 2008-12-09T14:12:02.887 回答
54

绝不。您永远无法确定应用程序能够执行下一行代码。如果你得到一个OutOfMemoryError,你不能保证你将能够可靠地做任何事情。捕获 RuntimeException 和检查的异常,但从不捕获错误。

http://pmd.sourceforge.net/rules/strictexception.html

于 2008-12-09T14:00:00.757 回答
16

通常,您应该始终捕获java.lang.Error并将其写入日志或将其显示给用户。我在支持部门工作,每天都看到程序员无法分辨程序中发生了什么。

如果你有一个守护线程,那么你必须防止它被终止。在其他情况下,您的应用程序将正常工作。

你应该只抓到java.lang.Error最高级别。

如果您查看错误列表,您会发现大多数都可以处理。例如ZipError,在读取损坏的 zip 文件时发生。

最常见的错误是OutOfMemoryErrorNoClassDefFoundError,它们在大多数情况下都是运行时问题。

例如:

int length = Integer.parseInt(xyz);
byte[] buffer = new byte[length];

可以产生一个OutOfMemoryError但它是一个运行时问题,没有理由终止你的程序。

NoClassDefFoundError如果库不存在或者您使用另一个 Java 版本,则通常会发生这种情况。如果它是您程序的可选部分,那么您不应该终止您的程序。

我可以举更多例子来说明为什么Throwable在顶层捕获并产生有用的错误消息是个好主意。

于 2009-03-05T12:29:59.960 回答
15

在多线程环境中,您最常想捕捉它!当您捕获它时,记录它并终止整个应用程序!如果你不这样做,一些可能正在执行某些关键部分的线程将会死掉,并且应用程序的其余部分会认为一切正常。因此,可能会发生许多不需要的情况。一个最小的问题是,如果其他线程由于一个线程不工作而开始抛出一些异常,您将无法轻松找到问题的根源。

例如,通常循环应该是:

try {
   while (shouldRun()) {
       doSomething();
   }
}
catch (Throwable t) {
   log(t);
   stop();
   System.exit(1);
}

即使在某些情况下,您也希望以不同的方式处理不同的错误,例如,在 OutOfMemoryError 上,您将能够定期关闭应用程序(甚至可能释放一些内存并继续),在其他一些情况下,您无能为力。

于 2009-03-07T16:39:26.737 回答
9

非常稀有。

我只会在线程的顶层说,以便尝试发出一条消息,说明线程死亡的原因。

如果你在一个为你做这类事情的框架中,把它留给框架。

于 2008-12-09T14:15:27.980 回答
6

几乎从不。错误被设计为应用程序通常无法解决的问题。唯一的例外可能是处理错误的呈现,但即使这样也可能不会按计划进行,具体取决于错误。

于 2008-12-09T13:59:06.407 回答
6

Error通常不应该被捕获,因为它表示不应该发生的异常情况

来自该类的 Java API 规范Error

AnError是它的子类,Throwable 它指示合理的应用程序不应尝试捕获的严重问题。大多数此类错误是异常情况。[...]

方法不需要在其 throws 子句中声明任何可能在方法执行期间抛出但未被捕获的 Error 子类,因为这些错误是不应该发生的异常情况。

正如规范中提到的,anError仅在有机会的情况下抛出,当 anError发生时,应用程序几乎无能为力,并且在某些情况下,Java 虚拟机本身可能处于不稳定状态(例如VirtualMachineError

虽然 anError是一个子类,Throwable这意味着它可以被子句捕获,但它可能并不是真正需要的,因为当JVM 抛出try-catchan 时应用程序将处于异常状态。Error

在第11.5 节 The Exception Hierarchy of the Java Language Specification, 2nd Edition中也有一个简短的部分。

于 2008-12-09T14:18:27.413 回答
6

如果您足够疯狂地创建一个新的单元测试框架,您的测试运行程序可能需要捕获任何测试用例抛出的 java.lang.AssertionError。

否则,请参阅其他答案。

于 2008-12-10T20:44:45.977 回答
5

还有其他几种情况,如果你发现一个错误,你必须重新抛出它。例如ThreadDeath永远不应该被捕获,如果你在一个封闭的环境(例如应用程序服务器)中捕获它,它可能会导致大问题:

只有在异步终止后必须进行清理时,应用程序才应捕获此类的实例。如果 ThreadDeath 被方法捕获,重要的是重新抛出它,以便线程真正死亡。

于 2008-12-09T14:09:10.113 回答
4

非常非常罕见。

我只为一个非常具体的已知案例做这件事。例如,如果两个独立的 ClassLoader加载相同的 DLL,则可能会抛出 java.lang.UnsatisfiedLinkError。(我同意我应该将 JAR 移动到共享类加载器)

但最常见的情况是您需要登录才能知道用户抱怨时发生了什么。您想要向用户发送消息或弹出窗口,而不是默默地死去。

即使是 C/C++ 中的程序员,他们也会弹出一个错误并在它退出之前告诉人们不理解的内容(例如内存故障)。

于 2008-12-09T14:28:55.037 回答
3

在 Android 应用程序中,我遇到了java.lang.VerifyError。我正在使用的库无法在具有旧版本操作系统的设备中运行,并且库代码将引发此类错误。我当然可以通过在运行时检查操作系统的版本来避免错误,但是:

  • 未来支持的最旧 SDK 可能会针对特定库进行更改
  • try-catch 错误块是更大的回退机制的一部分。一些特定的设备,虽然它们应该支持库,但会抛出异常。我捕获了 VerifyError 和所有异常以使用后备解决方案。
于 2013-03-14T06:17:07.087 回答
3

在测试环境中捕获 java.lang.AssertionError 非常方便......

于 2013-11-27T01:53:46.140 回答
2

理想情况下,我们不应该处理/捕获错误。但是根据框架或应用程序的要求,可能存在我们需要做的情况。假设我有一个 XML Parser 守护进程,它实现了消耗更多内存的DOM Parser 。如果有一个要求,比如 Parser 线程在得到OutOfMemoryError时不应该死掉,而是应该处理它并向应用程序/框架的管理员发送消息/邮件。

于 2014-05-05T18:22:03.150 回答
1

理想情况下,我们不应该在我们的 Java 应用程序中捕获 Error,因为它是一种异常情况。应用程序将处于异常状态,并可能导致乱码或给出一些严重错误的结果。

于 2011-01-26T06:23:27.300 回答
1

在检查断言的单元测试中捕获错误可能是合适的。如果有人禁用断言或以其他方式删除您想知道的断言

于 2012-08-19T20:35:49.697 回答
1

当 JVM 不再按预期工作或即将发生错误时,将出现错误。如果你捕捉到一个错误,就不能保证catch块会运行,更不能保证它会运行到最后。

还要看运行的电脑,当前的内存状态,所以没办法去测试,尽力而为。你只会有一个危险的结果。

您还将降低代码的可读性。

于 2013-04-23T16:50:35.757 回答