抛出异常
以下示例显示了抛出异常的基础知识:
public void checkNumber(int number) throws IllegalArgumentException {
if (number < 0) {
throw new IllegalArgumentException("Number must be positive: " + number);
}
}
在第 3 行抛出异常。本声明可分为两部分:
-
new IllegalArgumentException(...)
正在创建IllegalArgumentException
类的实例,并带有描述异常报告错误的消息。 -
然后
throw ...
抛出异常对象。
抛出异常时,会导致封闭语句异常终止,直到处理**异常为止。这在其他示例中描述。
最好在单个语句中创建和抛出异常对象,如上所示。在异常中包含有意义的错误消息也是一种很好的做法,可以帮助程序员理解问题的原因。但是,这不一定是你应向最终用户显示的消息。 (首先,Java 没有直接支持国际化异常消息。)
还有几点要做:
-
我们宣称
checkNumber
为throws IllegalArgumentException
。这不是绝对必要的,因为IllegalArgumentException
是一个经过检查的例外; 请参阅 Java 异常层次结构 - 未选中和已检查的异常 。但是,最好这样做,并且还要包含抛出方法的 javadoc 注释的异常。 -
无法访问
throw
语句后的代码。因此,如果我们写这个:throw new IllegalArgumentException("it is bad"); return;
编译器将报告
return
语句的编译错误。
链接异常
除了传统的 message
参数之外,许多标准异常都有一个带有第二个 cause
参数的构造函数。cause
允许你链接异常。这是一个例子。
首先,我们定义一个未经检查的异常,当我们的应用程序遇到不可恢复的错误时,它会抛出。请注意,我们已经包含了一个接受 cause
参数的构造函数。
public class AppErrorException extends RuntimeException {
public AppErrorException() {
super();
}
public AppErrorException(String message) {
super(message);
}
public AppErrorException(String message, Throwable cause) {
super(message, cause);
}
}
接下来,这是一些说明异常链接的代码。
public String readFirstLine(String file) throws AppErrorException {
try (Reader r = new BufferedReader(new FileReader(file))) {
String line = r.readLine();
if (line != null) {
return line;
} else {
throw new AppErrorException("File is empty: " + file);
}
} catch (IOException ex) {
throw new AppErrorException("Cannot read file: " + file, ex);
}
}
try
块中的 throw
检测到问题并通过简单消息通过异常报告。相比之下,catch
块中的 throw
通过将其包装在新的(已检查)异常中来处理 IOException
。但是,它并没有丢掉原来的例外。通过将 IOException
作为 cause
传递,我们将其记录下来,以便可以在堆栈跟踪中打印,如创建和读取堆栈跟踪中所述。