Ste*_*n C 5 java compiler-errors uncaught-exception checked-exceptions
新的 Java 程序员经常遇到如下错误:
"error: unreported exception <XXX>; must be caught or declared to be thrown"
Run Code Online (Sandbox Code Playgroud)
其中 XXX 是某个异常类的名称。
请解释:
首先要事。这是一个编译错误,并非例外。您应该在编译时看到它。
如果您在运行时异常消息中看到它,那可能是因为您正在运行一些包含编译错误的代码。返回并修复编译错误。然后在 IDE 中找到并设置防止它为存在编译错误的源代码生成“.class”文件的设置。(为自己节省未来的痛苦。)
这个问题的简短回答是:
错误消息表明,出现此错误的语句正在抛出(或传播)已检查的异常,并且该异常(该XXX)未得到正确处理。
解决方案是通过以下任一方式处理异常:
try ... catch语句捕获并处理它,或者throws函数1。1 - 在某些极端情况下您无法这样做。阅读答案的其余部分!
在 Java 中,异常由该类的派生类来表示java.lang.Throwable。异常分为两类:
Throwable、 和Exception及其子类,除了RuntimeException和 其子类。Error及其子类,RuntimeException及其子类。(上面的“子类”包括直接子类和间接子类。)
检查异常和非检查异常之间的区别在于,检查异常必须在它们发生的封闭方法或构造函数内“处理”,但不需要处理非检查异常。
(问:如何知道异常是否被检查?答:找到异常类的 javadoc,并查看其父类。)
从Java语言的角度来看,有两种处理异常的方法可以让编译器“满意”:
您可以在语句中捕获异常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
}
}
Run Code Online (Sandbox Code Playgroud)
IOException在上面,我们将抛出(checked) 的语句放在try. 然后我们写了一个catch子句来捕获异常。(我们可以捕获...的超类IOException,但在这种情况下,Exception捕获Exception是一个坏主意。)
您可以声明封闭方法或构造throws函数异常
public void doThings() throws IOException {
// do some things
if (someFlag) {
throw new IOException("cannot read something");
}
// do more things
}
Run Code Online (Sandbox Code Playgroud)
在上面我们已经声明了doThings()throws IOException。这意味着调用该doThings()方法的任何代码都必须处理异常。简而言之,我们将处理异常的问题传递给调用者。
以下哪些事情是正确的做法?
这取决于上下文。但是,一般原则是您应该在代码中能够适当处理异常的级别上处理异常。这又取决于异常处理代码将要执行的操作(位于HERE)。能恢复吗?它可以放弃当前的请求吗?是否应该停止申请?
回顾一下。编译错误的意思是:
你的解决过程应该是:
考虑本问答中的以下示例
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");
}
}
Run Code Online (Sandbox Code Playgroud)
如果您一直遵循我们到目前为止所说的内容,您将意识到这t()将给出“未报告的异常”编译错误。在本例中,错误在于t已声明为throws IllegalAccessException。事实上,异常不会传播,因为它已在抛出它的方法中被捕获。
此示例中的修复方法是删除.throws IllegalAccessException
这里的小教训是,该throws IllegalAccessException方法表明调用者应该预期异常会传播。这实际上并不意味着它会传播。另一方面是,如果您不希望异常传播(例如,因为它没有被抛出,或者因为它被捕获并且没有被重新抛出),那么该方法的签名不应该说它被抛出!
您应该避免做以下几件事:
不要将 catch Exception(或Throwable) 作为捕获异常列表的捷径。如果你这样做,你有可能捕获到你不期望的东西(比如未经检查的 NullPointerException),然后在你不应该的时候尝试恢复。
不要将方法声明为throws Exception. 这迫使被调用者处理(可能)任何已检查的异常......这是一场噩梦。
不要压制异常。例如
try {
...
} catch (NullPointerException ex) {
// It never happens ... ignoring this
}
Run Code Online (Sandbox Code Playgroud)
如果您抑制异常,则可能会使触发异常的运行时错误变得更难以诊断。你正在销毁证据。
注意:仅仅相信异常永远不会发生(根据评论)并不一定会成为事实。
在某些情况下,处理已检查的异常是一个问题。一种特殊情况是static初始化程序中的检查异常。例如:
private static final FileInputStream input = new FileInputStream("foo.txt");
Run Code Online (Sandbox Code Playgroud)
FileInputStream被声明为...,这throws FileNotFoundException是一个受检查的异常。但由于上面是一个字段声明,Java 语言的语法不允许我们将声明放在try...中catch。并且没有适当的(封闭的)方法或构造函数......因为此代码是在类初始化时运行的。
一种解决方案是使用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'
}
Run Code Online (Sandbox Code Playgroud)
(在实际代码中有更好的方法来处理上述场景,但这不是本示例的重点。)
如上所述,您可以捕获静态块中的异常。但我们没有提到的是,您必须捕获块内的已检查异常。静态块没有可以捕获已检查异常的封闭上下文。
lambda 表达式(通常)不应引发未经检查的异常。这并不是对 lambda本身的限制。相反,它是用于提供参数的参数的函数接口的结果。除非函数声明受检查异常,否则 lambda 不能抛出异常。例如:
List<Path> paths = ...
try {
paths.forEach(p -> Files.delete(p));
} catch (IOException ex) {
// log it ...
}
Run Code Online (Sandbox Code Playgroud)
即使我们看起来已经捕获了IOException,编译器也会抱怨:
catch捕获一个从未抛出的异常!事实上,异常需要在 lambda 本身中捕获:
List<Path> paths = ...
paths.forEach(p -> {
try {
Files.delete(p);
} catch (IOException ex) {
// log it ...
}
}
);
Run Code Online (Sandbox Code Playgroud)
delete(精明的读者会注意到,在 a抛出异常的情况下,两个版本的行为有所不同......)
我见过一个方法有一个throws Xyzzy子句的情况,编译器仍然抱怨必须Xyzzy“捕获或声明抛出”。例如:未报告的异常……必须捕获或声明抛出;尽管*抛出*关键字。
如果您发现自己处于这种情况,请仔细查看异常的完全限定名称。如果完全限定名称不同,则例外情况也不同。(相信编译器所说的并尝试理解它。)
Oracle Java 教程:
| 归档时间: |
|
| 查看次数: |
3385 次 |
| 最近记录: |