首先要做的事情。这是一个编译错误而不是例外。您应该在编译时看到它。
(如果您在运行时异常消息中看到它,那可能是因为您正在运行一些包含编译错误的代码。返回并修复编译错误,并在您的 IDE 中找到并设置防止它运行代码时出现编译错误。)
这个问题的简短回答是:
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
}
}
在上面,我们将抛出(检查的)IOException 的语句放在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
}
在上面我们已经声明doThings() 抛出IOException。这意味着任何调用doThings() 方法的代码都必须处理异常。简而言之,我们将处理异常的问题传递给调用者。
这些事情中哪些是正确的做法?
这取决于上下文。但是,一般原则是您应该在代码中能够适当处理异常的级别处理异常。而这又取决于异常处理代码将要做什么(HERE)。能恢复吗?它可以放弃当前的请求吗?它应该停止应用程序吗?
解决问题
回顾一下。编译错误的意思是:
- 您的代码已引发检查异常,或调用了引发检查异常的某些方法或构造函数,并且
- 它没有处理异常,通过捕获它或按照 Java 语言的要求声明它。
你的解决过程应该是:
- 了解异常的含义,以及为什么会抛出它。
- 根据1,决定正确的处理方式。
- 在 2 的基础上,对您的代码进行相关更改。
有例外的不良做法
有几件事是你应该避免做的:
-
不要将Exception(或Throwable)作为捕获异常列表的捷径。如果你这样做了,你就有责任捕捉到你不期望的东西(比如 unchecked NullPointerException),然后在你不应该的时候尝试恢复。
-
不要将方法声明为throws Exception。这迫使被调用者(可能)处理任何已检查的异常......这是一场噩梦。
-
不要压制异常。例如
try {
...
} catch (NullPointerException ex) {
}
如果您压制异常,您可能会使触发它们的运行时错误更难诊断。你在销毁证据。
边缘情况
在某些情况下处理检查的异常是一个问题。一种特殊情况是static 初始化程序中的检查异常。例如:
private static final FileInputStream input = new FileInputStream("foo.txt");
FileInputStream 被声明为throws FileNotFoundException ...这是一个检查异常。但是由于上面是一个字段声明,Java 语言的语法,不允许我们将声明放在 try ... catch 中。并且没有合适的(封闭的)方法或构造函数……因为这段代码是在 class 初始化时运行的。
一种解决方案是使用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'
}
(在实际代码中有更好的方法来处理上述场景,但这不是这个例子的重点。)