核心概念一句话总结
throw:主动抛出一个异常,它是动作,是创建并抛出异常对象的行为。throws:声明一个方法可能抛出哪些异常,它是声明,是告诉调用者“我可能会甩给你一些麻烦,你要准备好处理”。
throw 关键字
throw 用于在代码的任何地方手动抛出一个异常对象,这通常意味着你检测到了一个错误或异常情况,并决定中断当前方法的正常流程。

语法
throw new ExceptionType("异常信息");
ExceptionType:必须是Throwable类或其子类(如Exception,RuntimeException,IOException等)。"异常信息":是可选的,但强烈推荐提供,因为它可以帮助调试。
工作原理
当 throw 语句被执行时:
- 创建一个指定类型的异常对象。
- 当前方法的执行立即停止。
- 异常对象被“抛出”,并沿着调用栈向上寻找能够处理它的
catch块,如果找不到,程序就会终止。
使用场景
当你明确知道某个错误条件已经发生,需要中断程序流程时使用。
示例
public class CheckAge {
public static void checkAge(int age) {
// 如果年龄小于18,主动抛出一个 IllegalArgumentException
if (age < 18) {
// 创建一个异常对象并抛出
throw new IllegalArgumentException("年龄必须大于或等于18岁!");
}
System.out.println("年龄验证通过:" + age);
}
public static void main(String[] args) {
try {
checkAge(16); // 调用方法,传入不符合条件的参数
System.out.println("这行代码不会被执行。");
} catch (IllegalArgumentException e) {
// 捕获并处理 checkAge 方法抛出的异常
System.out.println("捕获到异常: " + e.getMessage());
}
System.out.println("程序继续执行...");
}
}
输出:
捕获到异常: 年龄必须大于或等于18岁!
程序继续执行...
throws 关键字
throws 用在方法签名中,用来声明该方法可能会抛出的一种或多种异常类型,它是一种“通知”机制,告诉方法的调用者:“我在执行过程中可能会发生这些异常,你需要处理它们”。

语法
修饰符 返回值类型 方法名(参数列表) throws 异常类型1, 异常类型2, ... {
// 方法体
}
工作原理
throws本身不会抛出异常,它只是声明。- 当一个方法使用
throws声明了异常后,调用这个方法的代码必须处理这个异常,处理方式有两种:- 使用
try-catch块捕获并处理异常。 - 在自己的方法签名上继续使用
throws声明,将异常向上传递给它的调用者。
- 使用
使用场景
当一个方法内部调用了另一个可能抛出受检异常的方法,而你不想(或不能)在该方法内部处理它时,就可以使用 throws。
示例
假设我们有一个读取文件的方法,它可能会抛出 IOException(这是一个受检异常,必须处理)。
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class FileReaderExample {
// 这个方法声明它可能会抛出 FileNotFoundException 和 IOException
public void readFile(String filePath) throws FileNotFoundException, IOException {
// FileInputStream 的构造函数可能会抛出 FileNotFoundException
FileInputStream fis = new FileInputStream(filePath);
// read() 方法可能会抛出 IOException
int data = fis.read();
while (data != -1) {
System.out.print((char) data);
data = fis.read();
}
fis.close();
}
public static void main(String[] args) {
FileReaderExample example = new FileReaderExample();
// main 方法调用 readFile,必须处理其声明的异常
try {
example.readFile("test.txt");
System.out.println("\n文件读取成功。");
} catch (FileNotFoundException e) {
System.out.println("错误:文件未找到!");
e.printStackTrace();
} catch (IOException e) {
System.out.println("错误:读取文件时发生IO异常!");
e.printStackTrace();
}
}
}
throw vs throws 核心区别
| 特性 | throw |
throws |
|---|---|---|
| 含义 | 抛出一个异常对象 | 声明一个方法可能抛出异常 |
| 语法位置 | 方法体内部 | 方法签名中,在参数列表之后 |
| 作用 | 手动中断程序流程,创建并抛出异常 | 告知调用者该方法可能产生的异常类型 |
| 与异常的关系 | 是一个动作,是异常的源头 | 是一个声明,是异常的声明 |
| 后续处理 | 抛出后,必须由 try-catch 捕获或程序终止 |
调用者必须使用 try-catch 或继续 throws |
| 数量 | 一次只能 throw 一个异常 |
可以 throws 多个异常,用逗号隔开 |
| 异常类型 | 可以抛出任何 Throwable 的子类 |
通常用于声明受检异常,但也可以声明非受检异常 |
一个综合示例来理解两者的关系
public class ThrowAndThrowsDemo {
// 方法一:声明它会抛出一个受检异常 IOException
public void readFile() throws IOException {
System.out.println("readFile: 准备读取文件...");
// 模拟文件读取失败,手动抛出一个异常
// 注意:这里也可以不 throw,而是调用一个会抛出 IOException 的方法
// new FileInputStream("non_existent_file.txt");
throw new IOException("无法打开文件,文件不存在或权限不足!");
}
// 方法二:声明它会抛出一个非受检异常 NullPointerException
public void processObject(Object obj) throws NullPointerException {
if (obj == null) {
// 手动抛出一个运行时异常
throw new NullPointerException("传入的对象不能为 null!");
}
System.out.println("processObject: 对象处理成功。");
}
// 方法三:它调用了可能抛出异常的方法,并选择自己处理
public void handleReadFileSafely() {
try {
System.out.println("handleReadFileSafely: 尝试调用 readFile...");
readFile(); // 调用声明了 throws 的方法
} catch (IOException e) {
System.out.println("handleReadFileSafely: 捕获到并处理了 IOException。");
e.printStackTrace();
}
}
// 方法四:它调用了可能抛出异常的方法,并选择继续向上抛出
public void processAndReThrow() throws IOException {
System.out.println("processAndReThrow: 调用 readFile 并选择不处理...");
readFile(); // 调用声明了 throws 的方法
// 因为 readFile 抛出 IOException,processAndReThrow 也必须 throws IOException
}
public static void main(String[] args) {
ThrowAndThrowsDemo demo = new ThrowAndThrowsDemo();
// 1. 调用自己处理异常的方法
demo.handleReadFileSafely();
System.out.println("--------------------");
// 2. 调用选择重新抛出异常的方法
try {
demo.processAndReThrow();
} catch (IOException e) {
System.out.println("main: 捕获了 processAndReThrow 传递上来的 IOException。");
}
System.out.println("--------------------");
// 3. 调用抛出非受检异常的方法
try {
demo.processObject(null); // 传入 null 触发异常
} catch (NullPointerException e) {
System.out.println("main: 捕获了 processObject 抛出的 NullPointerException。");
}
System.out.println("--------------------");
// 4. 调用抛出非受检异常的方法,不使用 try-catch
// 非受检异常是可选的,可以不处理,但程序会中断
System.out.println("准备调用 processObject(null) 且不捕获异常...");
demo.processObject(null); // 程序会在这里抛出异常并终止
System.out.println("这行代码不会被执行。");
}
}
throw是你作为程序员,在代码中主动制造一个异常事件。throws是你作为方法的设计者,向方法的使用者发出一个警告:“小心,我这里可能会出问题”。
理解了这两个角色的区别,就能很好地掌握 Java 的异常处理机制了。throw 是“行动派”,throws 是“声明派”。

