在 Java 的异常处理中,throw 关键字用于手动抛出一个异常对象,而 throws 关键字用于声明方法可能抛出的异常。下面详细介绍 Java 的最新异常处理机制及 try-catch-throw 的用法。
1. throw 关键字
throw 用于在代码中手动抛出一个异常,通常用于异常检测、错误处理或自定义异常。
throw 的作用
throw 关键字的主要作用是手动抛出异常,让程序在遇到错误时主动终止当前代码逻辑,并将异常交给上层代码处理。
在 Java 中,默认情况下,只有系统遇到错误时才会自动抛出异常,比如 NullPointerException、ArithmeticException 等。但有时候,我们需要自己定义错误情况,并主动抛出异常,让调用者知道发生了问题,这时候就用 throw。
语法:
示例:
1 2 3 4 5 6 7 8 9 10 11
| public class ThrowExample { public static void checkAge(int age) { if (age < 18) { throw new IllegalArgumentException("未成年人不能注册!"); } System.out.println("注册成功!"); } public static void main(String[] args) { checkAge(15); } }
|
throw 的使用场景
1. 校验输入参数
比如,我们要实现一个方法,它只能处理年龄 >= 18 的情况,如果年龄小于 18,就应该报错:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class ThrowExample { public static void checkAge(int age) { if (age < 18) { throw new IllegalArgumentException("未成年人不能注册!"); } System.out.println("注册成功!"); }
public static void main(String[] args) { checkAge(15); } }
|
执行结果:
1
| Exception in thread "main" java.lang.IllegalArgumentException: 未成年人不能注册!
|
👉 作用: 当 age < 18 时,我们主动抛出 IllegalArgumentException,让程序停止执行,并告诉调用者年龄不符合要求。
2. 避免错误值继续传播
假设我们有一个计算方法,但输入不能是负数,否则计算就没有意义:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class MathUtil { public static int sqrt(int num) { if (num < 0) { throw new ArithmeticException("负数不能开平方!"); } return (int) Math.sqrt(num); }
public static void main(String[] args) { System.out.println(sqrt(-9)); } }
|
执行结果:
1 2
| Exception in thread "main" java.lang.ArithmeticException: 负数不能开平方!
|
👉 作用: 这里如果不加 throw,Math.sqrt(-9) 可能会返回 NaN,影响计算结果。主动抛异常可以阻止错误继续传播,让调用者知道数据不合法。
3. 在 catch 里重新抛出异常
有时候,程序捕获异常后,仍然希望把异常抛出去,让上层代码处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class ReThrowExample { public static void divide(int a, int b) { try { int result = a / b; } catch (ArithmeticException e) { System.out.println("捕获异常,但继续抛出"); throw e; } }
public static void main(String[] args) { divide(10, 0); } }
|
执行结果:
1 2 3
| 捕获异常,但继续抛出 Exception in thread "main" java.lang.ArithmeticException: / by zero
|
👉 作用: 在 catch 里先记录日志,然后再用 throw 重新抛出异常,让外部调用者知道出错了。
4. 抛出自定义异常
如果 Java 自带的异常不够用,我们可以自己定义异常,并在 throw 里使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class MyException extends Exception { public MyException(String message) { super(message); } }
public class CustomThrowExample { public static void checkValue(int value) throws MyException { if (value > 100) { throw new MyException("数值不能大于 100!"); } }
public static void main(String[] args) { try { checkValue(150); } catch (MyException e) { System.out.println("自定义异常捕获:" + e.getMessage()); } } }
|
执行结果:
2. throws 关键字
throws 用于声明方法可能抛出的异常,让调用者知道这个方法可能会抛出异常。
语法:
1
| 返回类型 方法名(...) throws 异常类型1, 异常类型2 {
|
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class ThrowsExample { public static void readFile(String filePath) throws FileNotFoundException { File file = new File(filePath); Scanner scanner = new Scanner(file); } public static void main(String[] args) { try { readFile("test.txt"); } catch (FileNotFoundException e) { System.out.println("文件未找到: " + e.getMessage()); } } }
|
3. try-catch 捕获异常
try-catch 语句用于捕获异常,并在 catch 块中处理异常,而不会导致程序终止。
语法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| try { } catch (异常类型 变量) { } ````
**示例:**
java
复制编辑
`public class TryCatchExample { public static void main(String[] args) { try { int result = 10 / 0;
---
## 4. `try-with-resources`(最新 Java 处理方式)
Java 7 引入了 **try-with-resources**,用于自动关闭实现 `AutoCloseable` 接口的资源(如文件、网络连接)。
### 语法:
```Java try (资源声明) { } catch (异常类型 变量) { }
|
示例(自动关闭文件流):
1 2 3 4 5 6 7 8 9 10 11
| import java.io.*; public class TryWithResourcesExample { public static void main(String[] args) { try (BufferedReader reader = new BufferedReader(new FileReader("test.txt"))) { System.out.println(reader.readLine()); } catch (IOException e) { System.out.println("读取文件时发生错误: " + e.getMessage()); } } }
|
在 try 块结束后,BufferedReader 会自动关闭,无需手动调用 close()。
5. finally 语句
finally 块用于确保无论是否发生异常,都要执行的代码(例如资源释放)。
示例:
1 2 3 4 5 6 7 8 9 10 11
| public class FinallyExample { public static void main(String[] args) { try { int result = 10 / 0; } catch (ArithmeticException e) { System.out.println("发生异常: " + e.getMessage()); } finally { System.out.println("程序执行结束!"); } } }
|
即使发生异常,finally 依然会执行 "程序执行结束!"。
6. 自定义异常
如果 Java 现有异常类不能满足需求,可以自定义异常类(继承 Exception 或 RuntimeException)。
受检异常(必须 throws 处理)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| class MyCheckedException extends Exception { public MyCheckedException(String message) { super(message); } }
public class CustomExceptionExample { public static void validate(int num) throws MyCheckedException { if (num < 0) { throw new MyCheckedException("数字不能为负数!"); } }
public static void main(String[] args) { try { validate(-5); } catch (MyCheckedException e) { System.out.println("捕获异常: " + e.getMessage()); } } }
|
运行时异常(可选 throws 处理)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class MyRuntimeException extends RuntimeException { public MyRuntimeException(String message) { super(message); } }
public class CustomRuntimeExceptionExample { public static void validate(int num) { if (num < 0) { throw new MyRuntimeException("数字不能为负数!"); } }
public static void main(String[] args) { validate(-5); } }
|
运行时异常不强制 throws 处理。
7. 最新 Java 异常处理改进(Java 9+)
1. try-with-resources 资源管理改进
在 Java 9 之前,try-with-resources 只能在 try(资源) 中声明新资源;从 Java 9 开始,可以在 try 之外声明资源,然后在 try 语句中使用。
Java 9+ 示例:
1 2 3 4 5 6 7
| BufferedReader reader = new BufferedReader(new FileReader("test.txt")); try (reader) { System.out.println(reader.readLine()); } catch (IOException e) { System.out.println("读取文件时发生错误: " + e.getMessage()); }
|
2. 多异常捕获(Java 7+)
可以在一个 catch 块中捕获多个异常类型,提高代码简洁性。
示例:
1 2 3 4 5 6
| try { int num = Integer.parseInt("abc"); } catch (NumberFormatException | NullPointerException e) { System.out.println("发生异常: " + e.getMessage()); }
|
总结
| 关键字 |
作用 |
throw |
手动抛出异常 |
throws |
声明方法可能抛出的异常 |
try-catch |
捕获并处理异常 |
finally |
无论异常是否发生,都会执行 |
try-with-resources |
自动关闭资源(Java 7+) |
| 多异常捕获 |
一个 catch 处理多个异常(Java 7+) |
异常类
Java里面每个类都定义了异常类
所有的类都是Throwable的子类
Throwable派生了两个类
- Error (IOError, LinkageError)
- Exception (RuntimeError, 其他子类)
使用原则
- 在当前方法声明使用try-catch语句捕获异常
- 一个方法被覆盖时候,覆盖他的方法必须抛出相同的异常或者异常的子类
- 如果父类抛出多个异常,则覆盖他的方法必须抛出那些异常的一个子集,不能抛出新的异常。