未捕获 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 - 例如ThrowableError

基本上类型层次是:

       Object
         |
      Throwable
     /         \
Exception      Error

只有Throwables 和派生类可以被抛出,所以如果你抓住Throwable,那真的会抓住一切。

ThrowableException 以及源自Exception 的任何异常其他而不是源自RuntimeException 的异常都算作已检查异常 - 他们就是那些你必须声明你会抛出,或者如果你调用抛出它们的东西,你就会抓住它们。

总而言之,Java 异常层次结构有点混乱......

【讨论】:

错误并不是真正的异常,因此它们不是从异常派生的。 @R. Bemrose - 它们符合 Java 语言规范:“每个异常都由 Throwable 类或其子类之一的实例表示”和“未经检查的异常类是 RuntimeException 类及其子类,以及 Error 类及其子类。” 我很确定 Throwable 在技术上是一个“检查异常”。我最近考试弄错了。 这里也解释得很好(有类似的图表):geeksforgeeks.org/checked-vs-unchecked-exceptions-in-java【参考方案2】:

Errors 不是 Exceptions。

异常类及其子类 是 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 的子类。然而,在大多数情况下,捕获ErrorThrowable 并不是一个好主意,因为这些情况包括一些非常严重的错误情况,这些情况不容易恢复。您的恢复代码可能只会让事情变得更糟。

【讨论】:

是的。但是你可能还有更多的问题。例如如果/当你捕捉到 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毫秒后超时[重复]

Java中的异常的捕获和抛出是啥意思,有啥区别

Java - 线程以未捕获的异常退出(组 = 0x95d40b20)

php 异常处理 如何捕获异常??必须要抛出才可以吗?

JAVA 之 UNCAUGHTEXCEPTIONHANDLER异常处理机制