文档

Java™ 教程-Java Tutorials 中文版
把它们放在一起
Trail: Essential Classes
Lesson: Exceptions
Section: Catching and Handling Exceptions

把它们放在一起

前面的部分描述了如何为 ListOfNumbers 类中的 writeList 方法构造 trycatchfinally 代码块。现在,让我们来看看代码并调查会发生什么。

将所有组件放在一起时,writeList 方法如下所示。

public void writeList() {
    PrintWriter out = null;

    try {
        System.out.println("Entering" + " try statement");

        out = new PrintWriter(new FileWriter("OutFile.txt"));
        for (int i = 0; i < SIZE; i++) {
            out.println("Value at: " + i + " = " + list.get(i));
        }
    } catch (IndexOutOfBoundsException e) {
        System.err.println("Caught IndexOutOfBoundsException: "
                           +  e.getMessage());
                                 
    } catch (IOException e) {
        System.err.println("Caught IOException: " +  e.getMessage());
                                 
    } finally {
        if (out != null) {
            System.out.println("Closing PrintWriter");
            out.close();
        } 
        else {
            System.out.println("PrintWriter not open");
        }
    }
}

如前所述,此方法的 try 块有三种不同的退出可能性;这是其中两个。

  1. try 语句中的代码失败并引发异常。这可能是由 new FileWriter 语句引起的 IOException 或由 for 循环中的错误索引值引起的 IndexOutOfBoundsException
  2. 如一切都成功,则 try 语句正常退出。

让我们看看在这两种退出可能性期间 writeList 方法中会发生什么。

场景 1:发生异常

创建 FileWriter 的语句可能由于多种原因而失败。例如,如果程序无法创建或写入指示的文件,FileWriter 的构造函数将抛出 IOException

FileWriter 抛出 IOException 时,运行时系统立即停止执行 try 块;正在执行的方法调用未完成。然后,运行时系统开始在方法调用堆栈的顶部搜索适当的异常处理程序。在此示例中,当发生 IOException 时,FileWriter 构造函数位于调用堆栈的顶部。但是,FileWriter 构造函数没有适当的异常处理程序,因此运行时系统会在方法调用堆栈中检查下一个方法 — writeList 方法。writeList 方法有两个异常处理程序:一个用于 IOException,另一个用于 IndexOutOfBoundsException

运行时系统按照它们在 try 语句后出现的顺序检查 writeList 的处理程序。第一个异常处理程序的参数是 IndexOutOfBoundsException。这与抛出的异常类型不匹配,因此运行时系统会检查下一个异常处理程序 — IOException。这与抛出的异常类型相匹配,因此运行时系统结束其搜索适当的异常处理程序。现在运行时已找到适当的处理程序,执行 catch 块中的代码。

异常处理程序执行后,运行时系统将控制权传递给 finally 块。无论上面捕获的异常如何,finally 块中的代码都会执行。在这种情况下,FileWriter 从未打开过,不需要关闭。在 finally 块完成执行后,程序继续执行 finally 块之后的第一个语句。

以下是 ListOfNumbers 程序的完整输出,该程序在抛出 IOException 时出现。

Entering try statement
Caught IOException: OutFile.txt
PrintWriter not open 

以下列出的粗体代码显示了在此方案中执行的语句:

public void writeList() {
   PrintWriter out = null;

    try {
        System.out.println("Entering try statement");
        out = new PrintWriter(new FileWriter("OutFile.txt"));
        for (int i = 0; i < SIZE; i++)
            out.println("Value at: " + i + " = " + list.get(i));
                               
    } catch (IndexOutOfBoundsException e) {
        System.err.println("Caught IndexOutOfBoundsException: "
                           + e.getMessage());
                                 
    } catch (IOException e) {
        System.err.println("Caught IOException: " + e.getMessage());
    } finally {
        if (out != null) {
            System.out.println("Closing PrintWriter");
            out.close();
        } 
        else {
            System.out.println("PrintWriter not open");
        }
    }
}

场景 2:try 块正常退出

在这种场景下,try 块范围内的所有语句都成功执行,并且不会抛出异常。执行从 try 块的末尾开始,运行时系统将控制传递给 finally 块。因为一切都成功,当控件到达 finally 块时,PrintWriter 已打开,于是关闭 PrintWriter。同样,在 finally 块完成执行后,程序继续执行 finally 块之后的第一个语句。

当没有抛出异常时,这是 ListOfNumbers 程序的输出。

Entering try statement
Closing PrintWriter

以下示例中的粗体代码显示了在此场景中执行的语句。

public void writeList() {
    PrintWriter out = null;
    try {
        System.out.println("Entering try statement");
        out = new PrintWriter(new FileWriter("OutFile.txt"));
        for (int i = 0; i < SIZE; i++)
            out.println("Value at: " + i + " = " + list.get(i));
                  
    } catch (IndexOutOfBoundsException e) {
        System.err.println("Caught IndexOutOfBoundsException: "
                           + e.getMessage());

    } catch (IOException e) {
        System.err.println("Caught IOException: " + e.getMessage());
                                 
    } finally {
        if (out != null) {
            System.out.println("Closing PrintWriter");
            out.close();
        } 
        else {
            System.out.println("PrintWriter not open");
        }
    }
}

Previous page: The try-with-resources Statement
Next page: Specifying the Exceptions Thrown by a Method