"error: unreported exception <XXX>; must be caught or declared to be thrown"是什么意思,我该如何解决?



新的Java程序员经常遇到这样的错误:

"error: unreported exception <XXX>; must be caught or declared to be thrown" 

其中XXX是某个异常类的名称。

请解释:

  • 编译错误消息是怎么说的
  • 此错误背后的Java概念,以及
  • 如何修复

第一件事。这是一个编译错误,不是一个例外。您应该在编译时看到它。

如果您在运行时异常消息中看到它,那可能是因为您运行的某些代码中存在编译错误。请返回并修复编译错误。然后在IDE中找到并设置阻止它生成"的设置;。类";存在编译错误的源代码的文件。(为自己省去未来的痛苦。)


这个问题的简短答案是:

  • 错误消息表示,包含此错误的语句正在抛出(或传播)检查的异常,并且该异常(XXX)没有得到正确处理。

  • 解决方案是通过以下任一方式处理异常:

    • try ... catch语句捕获并处理它,或者
    • 声明封闭方法或构造函数CCD_ 3 it1

1-有些边缘情况下你无法做到这一点。阅读剩下的答案


已检查与未检查异常

在Java中,异常由java.lang.Throwable类的派生类表示。例外情况分为两类:

  • 除了RuntimeException及其子类之外,检查的异常ThrowableException及其子类
  • 未选中的异常是所有其他异常;即Error及其子类和RuntimeException及其子类

(在上文中,"子类"包括直接和间接子类。)

检查异常和未检查异常之间的区别在于,检查异常必须是";处理";在封闭方法或构造函数中发生异常,但不需要处理未检查的异常。

(问:你怎么知道是否检查了异常?答:找到异常类的javadoc,并查看其父类。)

如何处理(已检查的)异常

从Java语言的角度来看,有两种方法可以处理异常;满足";编译器:

  1. 您可以在try ... catch语句中捕获异常。例如:

    public void doThings() {
    try {
    // do some things
    if (someFlag) {
    throw new IOException("cannot read something");
    }
    // do more things
    } catch (IOException ex) {
    // deal with it    <<<=== HERE
    }
    }
    

    在上文中,我们将抛出(已检查的)IOException的语句放在try的主体中。然后我们编写了一个catch子句来捕获异常。(我们可以捕获IOException的超类……但在这种情况下,它将是Exception,捕获Exception是个坏主意。)

  2. 您可以声明封闭方法或构造函数throws为异常

    public void doThings() throws IOException {
    // do some things
    if (someFlag) {
    throw new IOException("cannot read something");
    }
    // do more things
    }  
    

    在上面我们已经声明了doThings()抛出IOException。这意味着任何调用doThings()方法的代码都必须处理该异常。简而言之,我们将处理异常的问题传递给调用者。

以下哪项是正确的做法?

这取决于上下文。然而,一般原则是,您应该在代码中能够适当处理异常的级别处理异常。这反过来又取决于异常处理代码要做什么(在HERE)。它能恢复吗?它能放弃当前的请求吗?它应该停止应用程序吗?

解决问题

概括一下。编译错误意味着:

  • 您的代码抛出了一个检查异常,或者调用了一些抛出检查异常的方法或构造函数,并且
  • 它没有通过捕获异常或按照Java语言的要求声明异常来处理

您的解决方案流程应该是:

  1. 了解异常的含义,以及为什么会被抛出。读取异常的javadoc和引发异常的方法
  2. 根据1,阅读您的代码,并决定处理可能的异常的正确方法
  3. 基于2,对代码进行相关更改

示例:用相同的方法投掷和接球

考虑下面这个问答的例子;

public class Main {
static void t() throws IllegalAccessException {
try {
throw new IllegalAccessException("demo");
} catch (IllegalAccessException e){
System.out.println(e);
}
}
public static void main(String[] args){
t();
System.out.println("hello");
}
}

如果你一直在关注我们到目前为止所说的,你会意识到t()将给出";未报告的异常";编译错误。在这种情况下,错误在于t已被声明为throws IllegalAccessException。事实上,异常不会传播,因为它已经在引发它的方法中被捕获

本例中的修复方法是删除throws IllegalAccessException

这里的小教训是throws IllegalAccessException是一个方法,它表示调用者应该期望传播异常。这实际上并不意味着它会传播。另一方面,如果不希望传播异常(例如,因为它没有被抛出,或者因为它被捕获而没有重新抛出),那么方法的签名就不应该说它被抛出了!

有例外的不良做法

有几件事你应该避免做:

  • 不要将Exception(或Throwable)作为捕获异常列表的捷径。如果你这样做,你很可能会发现你意想不到的事情(比如未检查NullPointerException),然后在不该恢复的时候尝试恢复。

  • 不要将方法声明为throws0。这迫使被调用处理(可能)任何已检查的异常。。。这简直是一场噩梦。

  • 不要压制例外情况。例如

    try { 
    ...
    } catch (NullPointerException ex) {
    // It never happens ... ignoring this
    }
    

    如果压缩异常,则可能会使触发异常的运行时错误更难诊断。你在破坏证据。

    注意:仅仅相信从未发生过异常(根据注释)并不一定会使其成为事实。

边缘情况:静态初始化程序

在某些情况下,处理已检查的异常是个问题。一种特殊情况是static初始化程序中的检查异常。例如:

private static final FileInputStream input = new FileInputStream("foo.txt");

FileInputStream被声明为throws FileNotFoundException。。。这是一个已检查的异常。但由于上面是一个字段声明,Java语言的语法不允许我们将声明放在try中。。。CCD_ 35。并且没有合适的(封闭的)方法或构造函数。。。因为这段代码是在初始化时运行的。

一种解决方案是使用static块;例如:

private static final FileInputStream input;
static {
FileInputStream temp = null;
try {
temp = new FileInputStream("foo.txt");
} catch (FileNotFoundException ex) {
// log the error rather than squashing it
}
input = temp;   // Note that we need a single point of assignment to 'input'
}

(在实际代码中有更好的方法来处理上述场景,但这不是本例的重点。)

边缘情况:静态块

如上所述,您可以在静态块中捕获异常。但我们没有提到的是,必须在块内捕获检查异常。静态块没有可以捕获已检查异常的封闭上下文。

边缘案例:lambdas

lambda表达式(通常)不应引发未检查的异常。这并不是对lambdas本身的限制。相反,它是用于提供参数的参数的函数接口的结果。除非函数声明了一个已检查的异常,否则lambda不能抛出一个异常。例如:

List<Path> paths = ...
try {
paths.forEach(p -> Files.delete(p));
} catch (IOException ex) {
// log it ...
}

即使我们似乎已经捕获了IOException,编译器也会抱怨:

  • lambda中有一个未捕获的异常,AND
  • CCD_ 38正在捕获从未抛出的异常

事实上,异常需要在lambda本身中捕获:

List<Path> paths = ...
paths.forEach(p -> {
try {
Files.delete(p);
} catch (IOException ex) {
// log it ...
}
}
);

(精明的读者会注意到,在delete抛出异常的情况下,这两个版本的行为不同…)

更多信息

Oracle Java教程:

  • 捕获或指定要求…还包括已检查和未检查的异常
  • 捕获和处理异常
  • 指定方法引发的异常

相关内容

  • 没有找到相关文章

最新更新