在什么情况下应该抓住java.lang.Error
应用程序?
一般来说,从不.但是,有时您需要捕获特定的错误.
如果您正在编写框架代码(加载第三方类),那么捕获LinkageErrors(没有发现类def,不满意的链接,不兼容的类更改)可能是明智的.我也看到一些愚蠢的第三方代码抛出错误的子句,所以你也必须处理它们.
顺便说一句,我不确定从OutOfMemory恢复是不可能的.
决不.您永远无法确定应用程序是否能够执行下一行代码.如果你得到了OutOfMemoryError
,你无法保证你能够可靠地做任何事情.捕获RuntimeException并检查异常,但从不出错.
http://pmd.sourceforge.net/rules/strictexception.html
通常,您应始终捕获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
顶层并产生有用的错误信息是一个好主意.
在多线程环境中,您最常想要抓住它!当你抓住它,记录它,并终止整个应用程序!如果你不这样做,一些可能正在做一些关键部分的线程将会死亡,应用程序的其余部分会认为一切正常.除此之外,许多不必要的情况都可能发生.一个最小的问题是,如果其他线程由于一个线程不起作用而开始抛出一些异常,那么您将无法轻松找到问题的根.
例如,通常循环应该是:
try { while (shouldRun()) { doSomething(); } } catch (Throwable t) { log(t); stop(); System.exit(1); }
即使在某些情况下,您也希望以不同的方式处理不同的错误,例如,在OutOfMemoryError上,您可以定期关闭应用程序(甚至可能释放一些内存,并继续),在其他一些情况下,您可以做的事情并不多.
非常稀有.
我只说在一个线程的顶层,以便尝试发出一条消息,其中包含线程死亡的原因.
如果您处于为您执行此类操作的框架中,请将其保留在框架中.
几乎从不.错误旨在成为应用程序通常无法执行任何操作的问题.唯一的例外可能是处理错误的呈现,但即使这可能不会按计划进行,具体取决于错误.
一个Error
通常不应该被捕获,因为它表明绝不应该出现的异常情况.
从类的Java API规范Error
:
An
Error
是一个子类Throwable
,表示合理的应用程序不应该试图捕获的严重问题.大多数此类错误都是异常情况.[...]一个方法不需要在其throws子句中声明在执行方法期间可能抛出但未捕获的任何Error类,因为这些错误是永远不应发生的异常情况.
正如规范所提到的那样,Error
只有在机会Error
出现的情况下,才会抛出,应用程序可以做的很少,并且在某些情况下,Java虚拟机本身可能处于不稳定状态(例如VirtualMachineError
)
虽然a Error
是一个子类Throwable
,意味着它可以被一个try-catch
子句捕获,但它可能并不真正需要,因为当Error
JVM抛出一个应用程序时,应用程序将处于异常状态.
第11.5节" Java语言规范的异常层次 " ,第2版中还有一个关于此主题的简短部分.
如果你疯狂到创建一个新的单元测试框架,你的测试运行器可能需要捕获任何测试用例抛出的java.lang.AssertionError.
否则,请参阅其他答案.
还有一些其他情况,如果你发现错误,你必须重新抛出它.例如,永远不应该捕获ThreadDeath,如果你在一个包含的环境(如应用服务器)中捕获它,它可能会导致很大的问题:
只有在异步终止后必须清理的情况下,应用程序才应捕获此类的实例.如果ThreadDeath被一个方法捕获,重要的是它被重新抛出,以便线程实际死亡.