理解 throw 用于主动抛出异常对象,而 throws 用于声明方法可能抛出的异常类型
掌握 throw 的使用场景(如自定义校验、手动触发异常)
掌握 throws 在方法签名中的作用及其对调用者的影响
能够正确处理检查型异常(Checked Exception)的编译期约束
区分 throw 与 throws 的语法位置、功能和适用范围
throw 是一个语句,用于在代码中显式抛出一个异常对象。该对象必须是 Throwable 类或其子类(如 Exception、RuntimeException)的实例。
throw new ExceptionType("错误描述");public class ThrowExample {
public static void main(String[] args) {
int numerator = 10;
int denominator = 0;
if (denominator == 0) {
throw new ArithmeticException("除数不能为零!");
}
System.out.println("结果: " + (numerator / denominator));
}
}输出:
Exception in thread "main" java.lang.ArithmeticException: 除数不能为零!
at ThrowExample.main(ThrowExample.java:6)关键点:
throw会立即中断当前方法执行控制流跳转到最近的匹配
catch块;若无匹配,则由 JVM 默认处理器终止程序
class RethrowDemo {
static void validateAge(int age) {
try {
if (age < 0) {
throw new IllegalArgumentException("年龄不能为负数");
}
System.out.println("年龄有效: " + age);
} catch (IllegalArgumentException e) {
System.out.println("在 validateAge 中捕获异常");
throw e; // 重新抛出,交由上层处理
}
}
public static void main(String[] args) {
try {
validateAge(-5);
} catch (IllegalArgumentException e) {
System.out.println("在 main 中处理异常: " + e.getMessage());
}
}
}输出:
在 validateAge 中捕获异常
在 main 中处理异常: 年龄不能为负数用途:在中间层记录日志或部分处理后,将异常传递给调用者做最终决策。
throws 是方法签名的一部分,用于告知调用者该方法可能抛出哪些检查型异常,从而将异常处理责任委托给调用方。
返回类型 方法名(参数列表) throws 异常类型1, 异常类型2 { ... }未处理检查型异常导致编译错误
public class CompileErrorExample {
public static void main(String[] args) {
Thread.sleep(1000); // 编译错误!
System.out.println("等待结束");
}
}编译错误:
error: unreported exception InterruptedException; must be caught or declared to be thrown原因:
Thread.sleep()声明了throws InterruptedException,属于检查型异常,必须处理。
使用 throws 委托异常处理
public class ThrowsExample {
public static void main(String[] args) throws InterruptedException {
Thread.sleep(1000); // 不再需要 try-catch
System.out.println("等待 1 秒后继续");
}
}输出:
等待 1 秒后继续此时异常处理责任被转移给 JVM(因为
main是程序入口),JVM 会终止程序并打印堆栈(若发生异常)。
自定义方法声明 throws
import java.io.*;
class FileProcessor {
// 声明该方法可能抛出 IOException
static void readFile(String path) throws IOException {
FileReader reader = new FileReader(path);
System.out.println("文件打开成功");
reader.close();
}
public static void main(String[] args) {
try {
readFile("missing.txt");
} catch (IOException e) {
System.out.println("文件操作失败: " + e.getMessage());
}
}
}输出(若文件不存在):
文件操作失败: missing.txt (No such file or directory)规则:调用声明了
throws检查型异常的方法时,调用者必须:
使用
try-catch捕获,或在自身方法签名中继续声明
throws
throw 与 throws优先使用标准异常(如 IllegalArgumentException、IllegalStateException),而非随意创建新异常。
在方法入口处校验参数,使用 throw 提前失败(Fail-Fast 原则)。
避免在 throws 中声明过多异常,可考虑封装为统一业务异常。
不要忽略检查型异常:即使暂时无法处理,也应记录日志或转换为运行时异常(谨慎使用)。
自定义异常时继承合适的父类:
业务逻辑错误 → 继承 RuntimeException(非检查型)
I/O 或外部依赖错误 → 继承 Exception(检查型)
throw 用于主动抛出异常实例,立即中断程序流。
throws 用于声明方法可能抛出的检查型异常,将处理责任转移给调用者。
检查型异常必须在编译期处理(try-catch 或 throws),非检查型异常则可选。
合理使用这两个关键字,可提升代码的健壮性、可读性和可维护性。
如果一个方法声明了 throws IOException,但内部并未抛出任何异常,这样写是否合法?有何影响?
能否在 catch 块中使用 throws?为什么?
如何设计一个自定义业务异常 InvalidOrderException,并在订单验证服务中使用 throw 和 throws?