首页 > 编程笔记 > Java笔记 阅读:27

Java try catch详解(附带实例)

在 Java 程序中,捕获异常是通过 try-catch 语句实现的,最基本的 try-catch 语句语法如下:
try {
    // 可能会发生异常的语句
} catch (Throwable e) {
    // 处理异常 e
}

Java try代码块

try 代码块中应该包含执行过程中可能会发生异常的语句。一条语句是否有可能发生异常,要看语句中调用的方法。

例如,日期格式化类 DateFormat 的日期解析方法 parse(),其完整定义如下:
try {
    // 可能会发生异常的语句
} catch (Throwable e) {
    // 处理异常 e
}
方法后面的 throws ParseException 说明:当调用 parse() 方法时有可能产生 ParseException 异常。
public Date parse(String source) throws ParseException
类方法、实例方法和构造方法都可以声明抛出异常,凡是抛出异常的方法都可以通过 try-catch 进行捕获,当然,运行时异常可以不捕获。一个方法声明抛出什么样的异常需要查询 API 文档。

Java catch代码块

每个 try 代码块可以伴随一个或多个 catch 代码块,用于处理 try 代码块中可能发生的多种异常。catch(Throwable e) 语句中的 e 是异常对象,e 必须是 Throwable 的子类,异常对象 e 的作用域在该 catch 代码块中。

下面看一个 try-catch 示例:
import java.util.Scanner;

public class ExceptionExample {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.print("请输入一个整数:");
        String input = scanner.nextLine();

        try {
            int number = Integer.parseInt(input);
            System.out.println("输入的整数是:" + number);
        } catch (NumberFormatException e) {
            System.out.println("输入的不是有效的整数。");
        }

        // 关闭 scanner
        scanner.close();
    }
}
在上面的示例中,使用 Scanner 获取用户输入的字符串,并尝试将其转换为整数。如果用户输入的字符串无法转换为整数,就会抛出 NumberFormatException 异常。

在 try 代码块中,尝试将字符串转换为整数,并打印输入的整数。如果用户输入的字符串无法转换为整数,则会跳转到 catch 代码块,捕获并处理 NumberFormatException 异常,并提示用户输入的不是有效的整数。

在 catch 代码块中处理了异常,并打印相应的错误信息。

无论是否发生异常,最后都会关闭 Scanner 资源,以确保程序在结束时正确释放资源。

如果在程序运行过程中输入的是非整数,则引发异常并打印“输入的不是有效的整数。”,如下图所示:


图 1 引发异常

如果输入的是有效的整数,则正常执行并打印“输入的整数是:×××”,如下图所示:


图 2 正常执行

代码解释如下:
代码第 ① 处创建了一个名为 scanner 的 Scanner 对象,用于从标准输入流(键盘)读取用户输入。将这个对象与 System.in 关联,以便从控制台接收输入。

代码第 ② 处的 String input = scanner.nextLine() 方法从用户输入中读取一行文本,并将其存储在名为 input 的字符串变量中。用户在控制台输入的内容会被保存在 input 变量中。

代码第 ③ 处开始一个 try 代码块,用于包含可能会引发异常的代码。在这个例子中,尝试将用户输入的字符串转换为整数。

代码第 ④ 处用 Integer.parseInt() 方法将 input 字符串转换为整数。如果 input 字符串无法转换为整数,就会抛出 NumberFormatException 异常。

代码第 ⑤ 处使用 catch 块捕获 NumberFormatException 异常,这是在 try 代码块中发生转换错误时会抛出的异常。

代码第 ⑥ 处的 scanner.close() 方法关闭 Scanner 对象。通过关闭 Scanner 对象,释放底层资源,即标准输入流(键盘),以确保在程序结束时正确释放资源。

使用多catch代码块

如果 try 代码块中有很多语句会发生异常,而且发生的异常种类又很多,那么可以在 try 后面跟多个 catch 代码块。多 catch 代码块的语法如下:
try {
    // 可能会发生异常的语句
} catch (Throwable e1) {
    // 处理异常 e1
} catch (Throwable e2) {
    // 处理异常 e2
} catch (Throwable e3) {
    // 处理异常 e3
    ...
}
在有多个 catch 代码块的情况下,当一个 catch 代码块捕获到一个异常时,其他的 catch 代码块就不再进行匹配。当捕获的多个异常类之间存在父子关系时,捕获异常顺序与 catch 代码块的顺序有关。一般先捕获子类,后捕获父类,否则捕获不到子类。

示例代码如下:
import java.util.Scanner;

class ExceptionExample {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        try {
            System.out.print("请输入一个整数:");
            String input = scanner.nextLine();
            int number = Integer.parseInt(input);
            System.out.println("输入的整数是:" + number);

            int dividend = 100;
            int result = dividend / number; // 尝试除以零的算术运算,引发 ArithmeticException 异常
            System.out.println("结果:" + result);
        } catch (NumberFormatException e) {
            System.out.println("输入的不是有效的整数。");
        } catch (ArithmeticException e) {
            System.out.println("发生了算术异常:" + e.getMessage());
        } catch (Exception e) {
            System.out.println("发生了其他异常。");
        }

        scanner.close();
    }
}
上述程序代码使用 Scanner 对象获取用户输入的整数,它尝试将输入解析为整数,使用 Integer.parseInt(input)。如果输入不是有效的整数,这一行可能会抛出 NumberFormatException 异常。

如果解析成功,程序将继续执行算术运算,即将 100 除以输入的数。如果输入的数是零(尝试除以零),这一行可能会抛出 ArithmeticException 异常。

程序使用多个 catch 代码块来处理不同类型的异常:
如果程序运行过程中输入的是 0,则引发除 0 异常,如下图所示,其他的异常情况不再测试。

Java finally语句

try-catch 语句后面还可以跟有一个 finally 代码块,无论 try 代码块正常结束还是 catch 代码块异常结束都会执行 finally 代码块,如下图所示。


图 3 finally代码块

使用 finally 代码块的示例代码如下:
import java.util.Scanner;

public class ExceptionExample {
    public static void main(String[] args) {
        Scanner scanner = null;
        try {
            scanner = new Scanner(System.in);
            System.out.print("请输入一个整数:");
            String input = scanner.nextLine();
            int number = Integer.parseInt(input);
            System.out.println("输入的整数是:" + number);

            int dividend = 100;
            int result = dividend / number; // 尝试除以零的算术运算,引发 ArithmeticException 异常
            System.out.println("结果:" + result);
        } catch (NumberFormatException e) {
            System.out.println("输入的不是有效的整数。");
        } catch (ArithmeticException e) {
            System.out.println("发生了算术异常:" + e.getMessage());
        } catch (Exception e) {
            System.out.println("发生了其他异常。");
        } finally {
            if (scanner != null) {
                // 确保无论发生什么情况,都关闭 Scanner 资源
                scanner.close();
                System.out.printf("资源已释放。");
            }
        }
    }
}
程序运行过程如下图所示,无论是否发生了异常,都保证执行了 finally 代码块:


图 4 执行finally代码块

Java自动资源管理

使用 finally 代码块释放资源会导致程序代码大量增加,一个 finally 代码块往往比正常执行的程序还要多。在 Java 7 之后提供的自动资源管理技术可以替代 finally 代码块,优化代码结构,提高程序可读性。

自动资源管理是在 try 语句上的扩展,语法如下:
try {
    // 声明或初始化资源语句
    // 可能会生成异常语句
} catch (Throwable e1) {
    // 处理异常 e1
} catch (Throwable e2) {
    // 处理异常 e2
    ...
} catch (Throwable eN) {
    // 处理异常 eN
}
在 try 语句后面添加一对小括号“()”,其中是声明或初始化资源语句,可以有多条语句,语句之间用分号“;”分隔。

示例代码如下:
import java.util.Scanner;

public class ExceptionExample {
    public static void main(String[] args) {
        try (Scanner scanner = new Scanner(System.in)) {
            System.out.print("请输入一个整数:");
            String input = scanner.nextLine();
            int number = Integer.parseInt(input);
            System.out.println("输入的整数是:" + number);

            int dividend = 100;
            int result = dividend / number; // 尝试除以零的算术运算,引发 ArithmeticException 异常
            System.out.println("结果:" + result);
        } catch (NumberFormatException e) {
            System.out.println("输入的不是有效的整数。");
        } catch (ArithmeticException e) {
            System.out.println("发生了算术异常:" + e.getMessage());
        } catch (Exception e) {
            System.out.println("发生了其他异常。");
        }
    }
}
在这个改进后的代码中,我们使用了自动资源管理 Scanner 对象。Scanner 类实现了 AutoCloseable 接口,因此在 try 代码块运行结束时会自动调用 scanner.close() 方法来关闭资源。无论代码是否发生异常,Scanner 对象都会被正确释放。这样的写法使代码更简洁,同时确保了资源的可靠释放。

相关文章