在Java的异常处理体系中,throws是一个用于方法声明的关键字,它的核心作用是告知调用方,当前方法在执行过程中可能会抛出哪些类型的异常,让调用方提前做好异常处理的准备。它属于异常声明的一部分,和主动抛出异常的throw关键字有着明确的分工。

throws关键字的基本语法
throws关键字需要紧跟在方法参数列表的后面,后面可以跟一个或多个异常类型,多个异常类型之间用逗号分隔。基本语法格式如下:
修饰符 返回值类型 方法名(参数列表) throws 异常类型1,异常类型2... {
// 方法体
}
下面是一个简单的使用示例,方法在读取文件时可能会抛出文件找不到的异常,因此用throws声明:
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class ThrowsDemo {
// 方法声明可能抛出FileNotFoundException
public void readFile(String filePath) throws FileNotFoundException {
// 创建文件输入流,可能触发文件找不到异常
FileInputStream fis = new FileInputStream(filePath);
}
}
throws关键字的核心作用
throws关键字的作用可以从两个维度理解:
- 异常类型告知:明确告诉方法的调用者,当前方法执行时可能会抛出哪些受检异常,调用者必须要么用try-catch捕获这些异常,要么继续用throws向上声明抛出。
- 异常传递:如果方法内部没有处理可能抛出的受检异常,就可以通过throws将异常抛给上层调用者,由上层决定如何处理,避免方法内部强行处理不合适的异常场景。
Java异常声明的相关规则
1. 受检异常必须声明
Java中的异常分为受检异常和非受检异常,受检异常是编译期就会检查的异常,比如IOException、SQLException等。如果方法内部可能产生受检异常,要么在方法内部用try-catch处理,要么必须用throws声明抛出,否则代码会编译失败。
非受检异常(继承自RuntimeException的异常,比如NullPointerException、IndexOutOfBoundsException)不强制要求用throws声明,因为这类异常通常是程序逻辑错误导致的,编译期不会检查。
2. 声明异常的范围规则
方法声明的异常类型可以是方法内部实际抛出的异常类型,也可以是这些异常类型的父类。比如方法内部可能抛出FileNotFoundException,也可以声明抛出它的父类IOException,甚至Exception,但是不建议声明范围过大,否则会失去异常声明的明确性。
3. 子类重写方法的异常声明限制
当子类重写父类的方法时,子类方法声明的异常类型不能超过父类方法声明的异常范围:
- 如果父类方法没有用throws声明任何异常,子类重写的方法也不能声明抛出受检异常。
- 子类方法声明的异常类型必须是父类方法声明异常类型的子类或者相同类型,不能声明抛出父类方法没有声明的更宽泛的受检异常。
下面的示例展示了重写时的异常声明规则:
import java.io.FileNotFoundException;
import java.io.IOException;
class Parent {
public void test() throws IOException {
// 父类方法声明抛出IOException
}
}
class Child extends Parent {
// 子类重写方法可以声明抛出IOException的子类FileNotFoundException,符合规则
@Override
public void test() throws FileNotFoundException {
// 方法体
}
}
throws和throw的区别
很多开发者容易混淆throws和throw,两者的核心区别如下:
| 对比维度 | throws | throw |
|---|---|---|
| 使用位置 | 方法声明的末尾 | 方法体内部 |
| 作用 | 声明方法可能抛出的异常类型 | 主动抛出一个具体的异常实例 |
| 后面跟的内容 | 异常类型(可以多个,逗号分隔) | 异常对象(只能一个) |
| 异常处理要求 | 受检异常必须要么处理要么继续声明 | 抛出的如果是受检异常,同样需要遵守throws的声明规则 |
下面的示例展示了throw和throws的配合使用:
import java.io.FileNotFoundException;
public class ThrowAndThrowsDemo {
public void checkFile(String filePath) throws FileNotFoundException {
if (filePath == null) {
// 主动抛出空指针相关的异常,这里用IllegalArgumentException(非受检)
throw new IllegalArgumentException("文件路径不能为空");
}
if (!filePath.endsWith(".txt")) {
// 主动抛出受检异常,因此方法需要用throws声明
throw new FileNotFoundException("仅支持txt文件");
}
}
}
使用throws的注意事项
- 不要滥用throws声明,不要为了省事把所有异常都声明为
Exception,这样会让调用方不清楚具体需要处理什么异常,降低代码的可读性。 - 如果方法内部已经用try-catch捕获并处理了异常,就不需要再用throws声明该异常,否则会让调用方误以为还需要处理。
- 在团队协作中,合理的throws声明可以让接口的使用者明确方法的异常风险,减少调用时的异常遗漏问题。
合理使用throws关键字可以让Java程序的异常处理逻辑更清晰,既明确了方法的异常边界,也给调用方足够的处理空间,是编写规范Java代码的重要部分。