何时赶上java.lang.Error?
在什么情况下应该在应用程序上捕获java.lang.Error
?
一般来说,从不。 但是,有时您需要捕获特定的错误。
如果你正在编写framework-ish代码(加载第三方类),那么捕获链接错误(没有find类的def,不满意的链接,不兼容的类更改)可能是明智的。 我也看到一些愚蠢的第三方代码抛出错误sublcasses,所以你将不得不处理这些。
顺便说一句,我不确定无法从OutOfMemory恢复。
决不。 你永远不能确定应用程序是否能够执行下一行代码。 如果您遇到OutOfMemoryError
,则不能保证您能够可靠地执行任何操作 。 Catch RuntimeException和检查exception,但从来没有错误。
通常你应该总是捕获java.lang.Error
并将其写入日志或显示给用户。 我支持工作,每天都看到程序员无法分辨程序中发生了什么。
如果你有一个守护线程,那么你必须防止它被终止。 在其他情况下您的应用程序将正常工作。
您应该只在最高级别捕获java.lang.Error
。
如果你看看错误列表,你会发现大部分都可以被处理。 例如,读取损坏的zip文件时发生ZipError
。
最常见的错误是OutOfMemoryError
和NoClassDefFoundError
,它们在大多数情况下都是运行时问题。
例如:
int length = Integer.parseInt(xyz); byte[] buffer = new byte[length];
可以产生一个OutOfMemoryError
但这是一个运行时问题,没有理由终止你的程序。
NoClassDefFoundError
主要发生在库不存在的情况下,或者您使用另一个Java版本时。 如果它是你的程序的一个可选部分,那么你不应该终止你的程序。
我可以举出更多的例子,说明为什么在顶层捕获Throwable
并产生有用的错误信息是一个好主意。
在multithreading环境中,你经常想要抓住它! 当你抓住它,logging下来,并终止整个应用程序! 如果你不这样做,那么可能会做一些关键部分的线程就会死机,其余的应用程序会认为一切都是正常的。 除此之外,许多不必要的情况可能会发生。 一个最小的问题是,如果其他线程由于一个线程不工作而开始抛出一些exception,您将无法轻易find问题的根源。
例如,通常循环应该是:
try { while (shouldRun()) { doSomething(); } } catch (Throwable t) { log(t); stop(); System.exit(1); }
即使在某些情况下,您也可能想要以不同的方式处理不同的错误,例如,在OutOfMemoryError上,您可以定期closures应用程序(甚至可能释放一些内存,然后继续),而在其他一些情况下,则可以做的事情不多。
非常稀有。
我只会说,在一个线程的顶级水平,以尝试发出一个线程死亡的原因的消息。
如果你在一个为你做这种事情的框架中,把它留给框架。
几乎从不。 错误被devise成应用程序通常不能做任何事情的问题。 唯一的例外可能是处理错误的表示,但即使这样也可能不会按计划进行,这取决于错误。
一个Error
通常不应该被捕获 ,因为它表示一个不应该发生的exception情况 。
从Error
类的Java API规范:
一个
Error
是Throwable
一个子类,表示一个合理的应用程序不应该试图捕捉的严重问题。 大多数这样的错误是exception的条件 […]一个方法不需要在throws子句中声明在执行该方法期间可能抛出的错误的任何子类,但是没有被捕获,因为这些错误是不应该发生的exception情况。
正如规范所提到的,只有在机会是Error
发生时才会抛出Error
,应用程序可以做的很less,在某些情况下,Java虚拟机本身可能处于不稳定状态(如VirtualMachineError
)
虽然Error
是Throwable
一个子类,这意味着它可以被try-catch
子句try-catch
,但它可能并不是真的需要,因为当JVM抛出一个Error
时,应用程序将处于一个不正常的状态。
在第11.5节“ Java语言规范 的例外层次结构 ” (第2版)中也有关于此主题的简短部分。
如果你疯狂地创build一个新的unit testing框架,你的testing运行器可能需要捕获任何testing用例抛出的java.lang.AssertionError。
否则,请参阅其他答案。
还有其他一些情况,如果你发现一个错误,你必须重新抛出它 。 例如ThreadDeath不应该被捕获,它可能会导致很大的问题是你在一个包含的环境(例如,一个应用程序服务器)中捕获它:
只有在asynchronous终止后,应用程序才能捕获此类的实例。 如果ThreadDeath被一个方法捕获,重新抛出它是非常重要的,这样线程就会死亡。
非常,很less。
我只做了一个非常非常具体的已知案例。 例如,如果两个独立的ClassLoader加载相同的DLL,则java.lang.UnsatisfiedLinkError可能被抛出。 (我同意我应该将JAR移动到共享类加载器)
但最常见的情况是,您需要login才能知道用户来抱怨时发生了什么。 你想给用户一个消息或popup窗口,而不是默默地死去。
即使是C / C ++的程序员,他们也会popup一个错误信息,告诉用户在退出之前不理解的内容(例如内存失败)。
在Android应用程序中,我正在捕获一个java.lang.VerifyError 。 我正在使用的库不适用于具有旧版本操作系统的设备,并且库代码会抛出这样的错误。 我当然可以通过在运行时检查OS的版本来避免错误,但是:
- 对于特定的库,未来最老的SDK可能会更改
- try-catch错误块是更大的回退机制的一部分。 一些特定的设备,虽然他们应该支持图书馆,抛出exception。 我捕获VerifyError和所有exception使用回退解决scheme。
在testing环境中捕获java.lang.AssertionError非常方便…
理想情况下,我们不应该处理/发现错误。 但是根据框架或应用的要求,可能有些情况需要我们去做。 说我有一个XMLparsing器守护进程,它实现DOMparsing器 ,消耗更多的内存。 如果有像Parser线程这样的需求,在得到OutOfMemoryError的时候不应该死掉,而是应该处理它,并发送一个消息/邮件给应用程序/框架的pipe理员。
理想情况下,我们不应该在Java应用程序中捕获错误,因为这是一个不正常的情况。 应用程序将处于不正常的状态,并可能导致错误或给出一些严重错误的结果。
在unit testing中发现检查断言的错误可能是合适的。 如果有人禁用了断言或者删除了你想知道的断言
当JVM没有像预期的那样工作,或者处于边缘时,会出现错误。 如果发现错误,则不能保证catch块将运行,甚至更less的运行直到结束。
它也将取决于正在运行的计算机,当前的内存状态,所以没有办法testing,尽力而为。 你只会有一个糟糕的结果。
您还将降级您的代码的可读性。
- ASP.NET MVC中的error handling
- Windows窗体应用程序中的exception处理最佳实践?
- 在C中有效使用goto进行错误pipe理?
- 在一行中捕获多个exception(块除外)
- 在BackgroundWorker中未处理的exception
- 在支持循环和函数的语言中使用“goto”是否有利? 如果是这样,为什么?
- 在Eclipse中增加堆空间:(java.lang.OutOfMemoryError)
- 我是否需要创build自己的InvalidArgumentException ..我无法find任何内置types在c#
- 如果在使用语句中发生exception,该对象是否仍然被处置?