Answers:
通常,永远不会。
但是,有时您需要捕获特定的错误。
如果您正在编写框架式的代码(加载第3方类),那么捕获LinkageError
(未找到类定义,未满足的链接,不兼容的类更改)可能是明智的。
我还看到了一些愚蠢的第三方代码抛出的子类Error
,因此您也必须处理这些子类。
顺便说一下,我不确定无法从中恢复OutOfMemoryError
。
决不。您永远不能确保应用程序能够执行下一行代码。如果得到了OutOfMemoryError
,则不能保证可以可靠地进行任何操作。捕获RuntimeException并检查异常,但不捕获错误。
boolean assertionsEnabled = false; assert assertionsEnabled = true;
通常,您应该始终捕获java.lang.Error
并写入日志或将其显示给用户。我在支持部门工作,每天都看到程序员无法分辨程序中发生了什么。
如果您有守护程序线程,则必须防止其终止。在其他情况下,您的应用程序将正常运行。
您应该只java.lang.Error
在最高级别上捕获。
如果查看错误列表,您会发现大多数错误都可以解决。例如ZipError
,在读取损坏的zip文件时发生a 。
最常见的错误是OutOfMemoryError
和NoClassDefFoundError
,在大多数情况下都是运行时问题。
例如:
int length = Integer.parseInt(xyz);
byte[] buffer = new byte[length];
可以产生一个,OutOfMemoryError
但这是一个运行时问题,没有理由终止您的程序。
NoClassDefFoundError
大多数情况是在没有库或使用其他Java版本的情况下发生的。如果它是程序的可选部分,则不应终止程序。
我可以举很多例子说明为什么Throwable
在顶层抓住一个好主意并产生有用的错误消息。
OutOfMemoryError
不是运行时错误,不能保证应用程序可以从中恢复。如果幸运的话,您可以加入OOM,new byte[largeNumber]
但是如果该分配不足以导致OOM,则可以在下一行或下一个线程中触发它。这是运行时问题,因为如果length
输入不受信任,则应在调用之前对其进行验证new byte[]
。
NoClassDefFoundError
可以在任何地方发生,因为在已编译的Java代码找不到类时会调用它。如果您的JDK配置不正确,它可能会因尝试使用java.util.*
类而触发,并且实际上无法针对它进行编程。如果可以选择包括依赖项,则应使用ClassLoader
它来检查是否存在依赖项(引发)ClassNotFoundException
。
ZipError
表示包含类的jar文件是损坏的zip文件。这是一个非常严重的问题,在这一点上,您不能相信要执行的任何代码,并且尝试从中“恢复”是不负责任的事情。
java.lang.Error
或java.lang.Throwable
在顶层尝试尝试执行某些操作可能会有所帮助-说记录错误消息。但是在那一点上,不能保证会被执行。如果您的JVM是OOMing,则尝试记录可能会分配更多String
s,从而触发另一个OOM。
在多线程环境中,您最经常想抓住它!当您捕获它时,将其记录下来并终止整个应用程序!如果您不这样做,则可能正在执行某些关键部分的线程将被终止,并且该应用程序的其余部分将认为一切正常。除此之外,还可能发生许多不需要的情况。一个最小的问题是,如果其他线程由于一个线程不起作用而开始引发某些异常,那么您将无法轻松找到问题的根源。
例如,通常循环应为:
try {
while (shouldRun()) {
doSomething();
}
}
catch (Throwable t) {
log(t);
stop();
System.exit(1);
}
即使在某些情况下,您也可能希望以不同的方式处理不同的错误,例如,在OutOfMemoryError上,您可以定期关闭应用程序(甚至可以释放一些内存,然后继续),而在其他情况下,则无能为力。
OutOfMemoryError
并继续而不是立即存在是不明智的,因为您的程序随后处于未定义状态。
一个Error
通常不应该被捕获,因为它表明绝不应该出现的异常情况。
从Error
该类的Java API规范中:
An
Error
是的子类,Throwable
它指示合理的应用程序不应尝试捕获的严重问题。大多数此类错误是异常情况。[...]不需要方法在throws子句中声明在方法执行期间可能抛出但未被捕获的Error的任何子类,因为这些错误是不应该发生的异常情况。
如规范所提到的,Error
仅在可能的情况下抛出an,当Error
发生时,应用程序几乎无能为力,并且在某些情况下,Java虚拟机本身可能处于不稳定状态(例如VirtualMachineError
)
尽管an Error
是它的子类Throwable
,意味着它可以被try-catch
子句捕获,但实际上并不需要它,因为当Error
JVM抛出。
在Java语言规范第二版的11.5节“异常层次结构”中也有关于此主题的一小节。
还有其他几种情况,如果您发现错误,则必须将其重新抛出。例如,永远不要捕获ThreadDeath,这可能会导致很大的问题,因为您是在包含环境中(例如应用程序服务器)捕获它的:
应用程序只有在异步终止后必须清除的情况下,才应捕获此类的实例。如果ThreadDeath被某个方法捕获,则将其重新抛出以使线程实际上死亡是很重要的。
Error
s。
在Android应用程序中,我捕获到java.lang.VerifyError。我正在使用的库无法在具有旧版操作系统的设备中使用,并且库代码将引发此类错误。我当然可以通过在运行时检查OS的版本来避免该错误,但是:
当JVM无法按预期运行或即将运行时,将出现错误。如果捕获到错误,则不能保证catch块将运行,甚至不能保证一直运行到最后。
它还将取决于正在运行的计算机,当前的内存状态,因此无法测试,尝试并尽力而为。您只会得到一个仓促的结果。
您还将降低代码的可读性。