抛出异常

以下示例显示了抛出异常的基础知识:

public void checkNumber(int number) throws IllegalArgumentException {
    if (number < 0) {
        throw new IllegalArgumentException("Number must be positive: " + number);
    }
}

在第 3 行抛出异常。本声明可分为两部分:

  • new IllegalArgumentException(...) 正在创建 IllegalArgumentException 类的实例,并带有描述异常报告错误的消息。

  • 然后 throw ... 抛出异常对象。

抛出异常时,会导致封闭语句异常终止,直到处理**异常为止。这在其他示例中描述。

最好在单个语句中创建和抛出异常对象,如上所示。在异常中包含有意义的错误消息也是一种很好的做法,可以帮助程序员理解问题的原因。但是,这不一定是你应向最终用户显示的消息。 (首先,Java 没有直接支持国际化异常消息。)

还有几点要做:

  • 我们宣称 checkNumberthrows 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 传递,我们将其记录下来,以便可以在堆栈跟踪中打印,如创建和读取堆栈跟踪中所述。