未捕获 Java 异常
Posted
技术标签:
【中文标题】未捕获 Java 异常【英文标题】:Java exception not caught 【发布时间】:2010-11-25 09:31:24 【问题描述】:为什么catch (Exception ex)
没有捕捉到Java 中的一些异常?这是代码完全失败并出现未处理的异常。 (Java 版本 1.4)。
public static void main(String[] args)
try
//Code ...
catch (Exception ex)
System.err.println("Caught Exception");
ex.printStackTrace();
exitCode = app.FAILURE_EXIT_CODE;
finally
app.shutdown();
System.exit(exitCode);
我收到了Exception in thread "main" java.lang.NoSuchMethodError
但是这行得通
public static void main(String[] args)
int exitCode = app.SUCCESS_EXIT_CODE;
try
//Code ...
catch (java.lang.NoSuchMethodError mex)
System.err.println("Caught NoSuchMethodError");
mex.printStackTrace();
exitCode = app.FAILURE_EXIT_CODE;
catch (Exception ex)
System.err.println("Caught Exception");
ex.printStackTrace();
exitCode = app.FAILURE_EXIT_CODE;
finally
app.shutdown();
System.exit(exitCode);
我收到Caught NoSuchMethodError java.lang.NoSuchMethodError:
我认为捕获异常会捕获所有异常?如何在 java 中捕获所有异常?
【问题讨论】:
【参考方案1】:因为某些异常并非源自 Exception
- 例如Throwable
和 Error
。
基本上类型层次是:
Object
|
Throwable
/ \
Exception Error
只有Throwables
和派生类可以被抛出,所以如果你抓住Throwable
,那真的会抓住一切。
Throwable
、Exception
以及源自Exception
的任何异常其他而不是源自RuntimeException
的异常都算作已检查异常 - 他们就是那些你必须声明你会抛出,或者如果你调用抛出它们的东西,你就会抓住它们。
总而言之,Java 异常层次结构有点混乱......
【讨论】:
错误并不是真正的异常,因此它们不是从异常派生的。 @R. Bemrose - 它们符合 Java 语言规范:“每个异常都由 Throwable 类或其子类之一的实例表示”和“未经检查的异常类是 RuntimeException 类及其子类,以及 Error 类及其子类。” 我很确定 Throwable 在技术上是一个“检查异常”。我最近考试弄错了。 这里也解释得很好(有类似的图表):geeksforgeeks.org/checked-vs-unchecked-exceptions-in-java【参考方案2】:Error
s 不是 Exception
s。
异常类及其子类 是 Throwable 的一种形式,表示 合理的条件 应用程序可能想要捕获。
-- JavaDoc for java.lang.Exception
错误是 Throwable 的子类 这表明严重的问题 合理的应用不应该尝试 赶上。
-- JavaDoc for java.lang.Error
您可能想要捕获某些错误,例如ThreadDeath。 ThreadDeath 被归类为错误,如下所述
ThreadDeath 类具体是 Error 的子类而不是 例外,即使它是“正常的 发生”,因为许多应用程序 捕获所有出现的异常和 然后丢弃异常。
-- JavaDoc for ThreadDeath
但是,由于 Thread 的 stop() 方法现在已被弃用,您不应该使用它,因此您永远不会看到 ThreadDeath。
【讨论】:
Java 语言规范不同意你的观点:“未经检查的异常类是 RuntimeException 类及其子类,以及 Error 类及其子类。” 我特别感谢关于不捕获错误的建议。考虑OutOfMemoryErrors
- 一旦被抛出,应用程序可能会处于错误状态。捕获并丢弃这种Error
是不明智的。
基本上,JLS 总是将“可以抛出和捕获的事物”称为异常。您在那里引用的任何内容都没有说明错误不是例外。【参考方案3】:
Exception 只是 Throwable 的一种; NoSuchMethodError 不是Exception,而是Error,是另一种Throwable。
【讨论】:
【参考方案4】:你可以赶上Throwable
。错误和异常扩展 Throwable
。
查看 Throwable JavaDoc:
Throwable 类是 Java 语言中所有错误和异常的超类。
【讨论】:
【参考方案5】:正如其他海报所指出的,并非所有可投掷对象都是Exception
的子类。然而,在大多数情况下,捕获Error
或Throwable
并不是一个好主意,因为这些情况包括一些非常严重的错误情况,这些情况不容易恢复。您的恢复代码可能只会让事情变得更糟。
【讨论】:
是的。但是你可能还有更多的问题。例如如果/当你捕捉到 OutOfMemoryError 会发生什么?【参考方案6】:首先让我们澄清一下本次讨论中一些不幸的语义混淆。有java.lang.Exception
类,我们可以简单地将其称为带有大写“E”的异常。然后你有一个小写“e”的例外,这是一种语言特性。您可以在documentation 中看到Throwable
类的小写版本:
为了在编译时检查异常,Throwable 和 Throwable 的任何子类,但不是两者的子类 RuntimeException 或 Error 被视为已检查的异常。
对我来说,将这个问题的答案视为已检查与未检查的异常(小写 e)更容易。已检查的异常必须在编译时考虑,而未检查的异常则不需要。异常(大写 E)及其子类是已检查异常,这意味着您要么必须捕获代码可能抛出的任何异常,要么声明您的方法可能抛出的异常(如果未捕获)。
Error 及其子类是未经检查的异常,这意味着您的代码既不必捕获可能抛出的错误,也不必声明您抛出这些错误。 RunTimeException 及其子类也是未经检查的异常,尽管它们位于类层次结构中。
考虑以下代码:
void test()
int a = 1, b = 0, c = a / b;
运行时,上面的代码会产生一个java.lang.ArithmeticException
。即使抛出异常并且代码既没有捕获 ArithmeticException 也没有声明它抛出了这个异常,这也将编译而没有任何错误。这就是未检查异常的本质。
考虑ArithmeticException
在类层次结构中的位置,尤其是它是java.lang.Exception 的子类这一事实。这里有一个派生自 java.lang.Exception 的异常,但因为它也是 java.lang.RuntimeException 的子类,所以它是一个未经检查的异常,因此您不必捕获它。
java.lang.Object
java.lang.Throwable
java.lang.Exception
java.lang.RuntimeException
java.lang.ArithmeticException
如果您想捕捉任何可能被抛出的东西,请捕捉 Throwable。然而,这可能不是最安全的做法,因为其中一些 Throwable 可能是致命的运行时条件,可能不应该被捕获。或者,如果您确实捕获了 Throwable,您可能想要重新抛出您无法处理的 Throwable。这取决于上下文。
【讨论】:
【参考方案7】:正如其他两篇文章所指出的,catch(Exception e) 仅适用于派生自 Exception 的异常。但是,如果您查看树层次结构,您会注意到 Throwable 时出现异常。 Throwable 也是Error 的基类。因此,在 NoSuchMethodError 的情况下,它是错误而不是异常。请注意命名约定 *Error 与 *Exception(例如 IOException)。
【讨论】:
以上是关于未捕获 Java 异常的主要内容,如果未能解决你的问题,请参考以下文章
终结器 java.lang.IllegalStateException 引发的未捕获异常:Binder 已终结
错误yarn.ApplicationMaster:未捕获的异常:java.util.concurrent.TimeoutException:期货在100000毫秒后超时[重复]