在什么情况下应该在应用程序上捕获java.lang.Error
?
答案 0 :(得分:96)
一般来说,永远不会。 但是,有时您需要捕获特定的错误。
如果你正在编写框架代码(加载第三方类),那么捕获LinkageErrors(没有发现类def,不满意的链接,不兼容的类更改)可能是明智的。 我也看到一些愚蠢的第三方代码抛出错误的子句,所以你必须处理这些。
顺便说一句,我不确定是否无法从OutOfMemory中恢复。
答案 1 :(得分:50)
从不。您永远无法确定应用程序是否能够执行下一行代码。如果您获得OutOfMemoryError
,则可以no guarantee that you will be able to do anything reliably。 Catch RuntimeException和checked Exceptions,但从不出错。
答案 2 :(得分:15)
通常,您应始终捕获java.lang.Error
并将其写入日志或将其显示给用户。我支持并且每天看到程序员无法分辨程序中发生了什么。
如果你有一个守护程序线程,那么你必须防止它被终止。在其他情况下,您的应用程序将正常工作。
你应该只抓住最高级别的java.lang.Error
。
如果查看错误列表,您会发现大多数错误都可以处理。例如,在读取损坏的zip文件时会出现ZipError
。
最常见的错误是OutOfMemoryError
和NoClassDefFoundError
,这些错误在大多数情况下都是运行时问题。
例如:
int length = Integer.parseInt(xyz);
byte[] buffer = new byte[length];
可以产生OutOfMemoryError
,但这是一个运行时问题,没有理由终止你的程序。
NoClassDefFoundError
主要发生。如果它是您程序的可选部分,那么您不应该终止您的程序。
我可以提供更多示例,说明为什么在顶层捕获Throwable
并产生有用的错误消息是个好主意。
答案 3 :(得分:14)
在多线程环境中,您最常想要抓住它!当你抓住它,记录它,并终止整个应用程序!如果你不这样做,一些可能正在做一些关键部分的线程将会死亡,应用程序的其余部分会认为一切正常。除此之外,许多不必要的情况都可能发生。 一个最小的问题是,如果其他线程由于一个线程不起作用而开始抛出一些异常,你将无法轻易找到问题的根。
例如,通常循环应该是:
try {
while (shouldRun()) {
doSomething();
}
}
catch (Throwable t) {
log(t);
stop();
System.exit(1);
}
即使在某些情况下,您也希望以不同的方式处理不同的错误,例如,在OutOfMemoryError上,您可以定期关闭应用程序(甚至可以释放一些内存,并继续),在其他一些情况下,您的数据并不多能做到。
答案 4 :(得分:8)
很少。
我只是说在一个线程的顶级,以便ATTEMPT发出一条消息,说明线程死亡的原因。
如果您处于为您做这类事情的框架中,请将其留在框架中。
答案 5 :(得分:6)
几乎没有。错误旨在成为应用程序通常无法执行任何操作的问题。唯一的例外可能是处理错误的呈现,但即使这可能不会按计划进行,具体取决于错误。
答案 6 :(得分:6)
通常不应该抓住Error
,因为表示不应该发生的异常情况。
来自Error
类的Java API规范:
Error
是Throwable
的子类 这表明存在严重的问题 合理的申请不应该尝试 去抓。大多数此类错误都是 异常情况。 [...]声明输入不需要方法 它的throws子句的任何子类 在期间可能抛出的错误 执行方法但不是 抓住了,因为这些错误是 不应该的异常情况 发生。
正如规范所提到的那样,Error
仅在某些情况下被抛出
当Error
发生时,应用程序可以做的很少,并且在某些情况下,Java虚拟机本身可能处于不稳定状态(例如VirtualMachineError
)
虽然Error
是Throwable
的子类,这意味着它可以被try-catch
子句捕获,但它可能并不真正需要,因为应用程序将在JVM抛出Error
时的异常状态。
11.5 The Exception Hierarchy的Java Language Specification, 2nd Edition部分还有关于此主题的简短部分。
答案 7 :(得分:6)
如果你疯狂到创建一个新的单元测试框架,你的测试运行器可能需要捕获任何测试用例抛出的java.lang.AssertionError。
否则,请参阅其他答案。
答案 8 :(得分:5)
还有一些其他情况,如果你发现错误, 必须重新抛出 。例如,永远不应该捕获ThreadDeath,如果你在一个包含的环境(如应用服务器)中捕获它会导致很大的问题:
只有在必须清理的情况下,应用程序才应捕获此类的实例 异步终止后。如果ThreadDeath被方法捕获, 重新抛出它以使线程实际死亡是很重要的。
答案 9 :(得分:4)
很少,很少。
我只为一个非常具体的已知病例做过。 例如,如果两个独立ClassLoader 加载相同的DLL,则可能抛出java.lang.UnsatisfiedLinkError。 (我同意我应该将JAR移动到共享的类加载器)
但最常见的情况是您需要登录才能知道用户投诉时发生了什么。你想要一条消息或弹出窗口给用户,而不是默默地死去。
即使是C / C ++中的程序员,他们也会弹出一个错误并在退出之前告诉人们不理解的东西(例如内存故障)。
答案 10 :(得分:3)
在Android应用程序中,我正在捕捉java.lang.VerifyError。我正在使用的库将无法在具有旧版本操作系统的设备中工作,并且库代码将引发此类错误。我当然可以通过在运行时检查操作系统的版本来避免错误,但是:
答案 11 :(得分:3)
在测试环境中捕获java.lang.AssertionError非常方便......
答案 12 :(得分:2)
理想情况下,我们不应该处理/捕获错误。但根据框架或应用程序的要求,可能存在我们需要做的情况。假设我有一个XML Parser守护程序,它实现了 DOM Parser ,它消耗更多的内存。如果有一个类似Parser线程的要求,当它变为 OutOfMemoryError 时不应该死亡,而是它应该处理它并向应用程序/框架的管理员发送消息/邮件。
答案 13 :(得分:1)
理想情况下,我们不应该在Java应用程序中捕获Error,因为它是一种异常情况。应用程序将处于异常状态,可能导致运输或出现严重错误的结果。
答案 14 :(得分:1)
在检查断言的单元测试中捕获错误可能是合适的。如果有人禁用断言或以其他方式删除您想要知道的断言
答案 15 :(得分:1)
当JVM不再按预期工作或接近时,会出现错误。如果你发现错误,就不能保证catch块会运行,甚至不会保证它会一直运行到最后。
它还将取决于正在运行的计算机,当前的内存状态,因此无法测试,尝试并尽力而为。你只会有一个不幸的结果。
您还会降低代码的可读性。