Skip to content

15.2 try…catch…finally

try…catch…finally 的概念

try-catch-finally 是 Java 中用于捕获和处理异常的基本结构。它允许我们:

  1. 尝试执行可能抛出异常的代码(try 块)
  2. 捕获并处理异常(catch 块)
  3. 无论是否发生异常,都执行清理代码(finally 块)

try…catch…finally 的语法

java
try {
    // 可能抛出异常的代码
} catch (ExceptionType1 e1) {
    // 处理 ExceptionType1 类型的异常
} catch (ExceptionType2 e2) {
    // 处理 ExceptionType2 类型的异常
} finally {
    // 无论是否发生异常,都会执行的代码
}

try 块

try 块包含可能抛出异常的代码。当 try 块中的代码抛出异常时,程序会跳转到对应的 catch 块。

示例

java
try {
    int[] numbers = {1, 2, 3};
    System.out.println(numbers[5]); // 可能抛出 ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("数组索引越界: " + e.getMessage());
}

catch 块

catch 块用于捕获并处理特定类型的异常。一个 try 块可以有多个 catch 块,每个 catch 块处理一种类型的异常。

多个 catch 块的顺序

当使用多个 catch 块时,应该按照异常的层次结构从具体到一般的顺序排列,即先捕获子类异常,再捕获父类异常。

示例

java
try {
    int[] numbers = {1, 2, 3};
    System.out.println(numbers[5]);
} catch (ArrayIndexOutOfBoundsException e) {
    System.out.println("数组索引越界: " + e.getMessage());
} catch (Exception e) {
    System.out.println("其他异常: " + e.getMessage());
}

catch 块中的异常对象

catch 块中的异常对象包含了异常的信息,如异常消息、堆栈跟踪等。

示例

java
try {
    int result = 10 / 0; // 可能抛出 ArithmeticException
} catch (ArithmeticException e) {
    System.out.println("异常消息: " + e.getMessage());
    System.out.println("异常类名: " + e.getClass().getName());
    e.printStackTrace(); // 打印堆栈跟踪
}

finally 块

finally 块中的代码无论是否发生异常,都会执行。它通常用于释放资源,如关闭文件、数据库连接等。

示例

java
import java.io.FileInputStream;
import java.io.IOException;

public class FinallyExample {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("example.txt");
            // 读取文件
            System.out.println("读取文件成功");
        } catch (IOException e) {
            System.out.println("文件操作异常: " + e.getMessage());
        } finally {
            // 确保资源被释放
            if (fis != null) {
                try {
                    fis.close();
                    System.out.println("文件已关闭");
                } catch (IOException e) {
                    System.out.println("关闭文件异常: " + e.getMessage());
                }
            }
        }
        System.out.println("程序继续执行");
    }
}

finally 块的执行情况

无论 try 块是否抛出异常,无论 catch 块是否捕获异常,finally 块都会执行。即使在 try 或 catch 块中使用了 return 语句,finally 块也会在 return 之前执行。

示例

java
public class FinallyExecutionExample {
    public static void main(String[] args) {
        System.out.println(testFinally());
    }
    
    public static int testFinally() {
        try {
            System.out.println("执行 try 块");
            return 1;
        } catch (Exception e) {
            System.out.println("执行 catch 块");
            return 2;
        } finally {
            System.out.println("执行 finally 块");
        }
    }
}

输出

执行 try 块
执行 finally 块
1

try-with-resources 语句

Java 7 引入了 try-with-resources 语句,用于自动关闭实现了 AutoCloseable 接口的资源,如文件流、数据库连接等。

语法

java
try (ResourceType resource1 = new ResourceType();
     ResourceType resource2 = new ResourceType()) {
    // 使用资源
} catch (Exception e) {
    // 处理异常
}
// 资源自动关闭,不需要 finally 块

示例

java
import java.io.FileInputStream;
import java.io.IOException;

public class TryWithResourcesExample {
    public static void main(String[] args) {
        try (FileInputStream fis = new FileInputStream("example.txt")) {
            // 读取文件
            System.out.println("读取文件成功");
        } catch (IOException e) {
            System.out.println("文件操作异常: " + e.getMessage());
        }
        // 资源自动关闭
        System.out.println("程序继续执行");
    }
}

嵌套的 try-catch 块

try-catch 块可以嵌套使用,即在 try 块或 catch 块中包含另一个 try-catch 块。

示例

java
public class NestedTryCatchExample {
    public static void main(String[] args) {
        try {
            int[] numbers = {1, 2, 3};
            try {
                System.out.println(numbers[5]); // 可能抛出 ArrayIndexOutOfBoundsException
            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("内部 catch: 数组索引越界");
                // 可能抛出其他异常
                int result = 10 / 0; // 可能抛出 ArithmeticException
            }
        } catch (ArithmeticException e) {
            System.out.println("外部 catch: 算术异常");
        }
        System.out.println("程序继续执行");
    }
}

示例:try-catch-finally 的应用

示例 1:文件操作

java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class FileOperationExample {
    public static void main(String[] args) {
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader("example.txt"));
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("文件操作异常: " + e.getMessage());
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    System.out.println("关闭文件异常: " + e.getMessage());
                }
            }
        }
    }
}

示例 2:使用 try-with-resources

java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class TryWithResourcesFileExample {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader("example.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        } catch (IOException e) {
            System.out.println("文件操作异常: " + e.getMessage());
        }
        // 资源自动关闭
    }
}

示例 3:多个资源

java
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

public class MultipleResourcesExample {
    public static void main(String[] args) {
        try (BufferedReader reader = new BufferedReader(new FileReader("input.txt"));
             BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                writer.write(line);
                writer.newLine();
            }
            System.out.println("文件复制成功");
        } catch (IOException e) {
            System.out.println("文件操作异常: " + e.getMessage());
        }
        // 资源自动关闭
    }
}

常见问题

1. finally 块中的异常

症状:finally 块中的代码抛出异常,会覆盖 try 或 catch 块中的异常

解决方案:在 finally 块中处理异常,或确保 finally 块不会抛出异常

示例

java
try {
    int result = 10 / 0; // 抛出 ArithmeticException
} catch (ArithmeticException e) {
    System.out.println("捕获到算术异常");
} finally {
    // 错误:finally 块中的异常会覆盖前面的异常
    int result = 10 / 0; // 抛出 ArithmeticException
}

2. try-with-resources 中的资源顺序

症状:多个资源的关闭顺序不正确

解决方案:资源的关闭顺序与声明顺序相反

示例

java
// 资源关闭顺序:writer 先关闭,然后 reader 关闭
try (BufferedReader reader = new BufferedReader(new FileReader("input.txt"));
     BufferedWriter writer = new BufferedWriter(new FileWriter("output.txt"))) {
    // 使用资源
}

3. 忽略异常

症状:捕获异常后不做任何处理

解决方案:捕获异常后应该进行适当的处理,如记录日志、通知用户等

示例

java
// 错误:忽略异常
try {
    // 可能抛出异常的代码
} catch (Exception e) {
    // 什么都不做
}

// 正确:处理异常
try {
    // 可能抛出异常的代码
} catch (Exception e) {
    System.out.println("发生异常: " + e.getMessage());
    // 其他处理逻辑
}

最佳实践

  1. 捕获具体的异常:尽量捕获具体的异常类型,而不是捕获所有异常

  2. 正确排序 catch 块:按照异常的层次结构从具体到一般的顺序排列 catch 块

  3. 使用 finally 块释放资源:对于需要释放的资源,使用 finally 块确保资源被释放

  4. 使用 try-with-resources:对于实现了 AutoCloseable 接口的资源,使用 try-with-resources 自动关闭

  5. 处理异常:捕获异常后应该进行适当的处理,而不是简单地打印错误信息

  6. 避免在 finally 块中抛出异常:finally 块中的异常会覆盖 try 或 catch 块中的异常

  7. 不要忽略异常:不要捕获异常后不做任何处理

总结

try-catch-finally 是 Java 中用于捕获和处理异常的基本结构:

  1. try 块:包含可能抛出异常的代码
  2. catch 块:捕获并处理特定类型的异常
  3. finally 块:无论是否发生异常,都会执行的代码,通常用于释放资源

Java 7 引入的 try-with-resources 语句可以自动关闭实现了 AutoCloseable 接口的资源,简化了代码。

通过合理使用 try-catch-finally 结构,可以提高代码的健壮性和可维护性。

© 2026 编程马·菜鸟教程 版权所有