throw和throws的区别是什么

一、总览

1.一句话区分:

✅ throw是"扔出"一个异常对象

✅ throws是"声明"这个方法可能会扔出异常

2.具体区别详解(结合例子)

关键词

含义

作用场景

是否放在方法签名中

是否后面跟异常对象

throw

实际扔出一个异常实例

在方法体内部真正抛出异常

❌ 否

✅ 是(对象)

throws

声明这个方法可能抛异常

在方法声明处告诉别人我可能出错

✅ 是

❌ 否(类名)

3.看两个完整的例子(贴近实际项目)

🚀 场景一:系统找不到客户数据 → 抛出业务异常

public void checkCustomer(String custId) {
    if (custId == null) {
        throw new BusinessException("客户ID不能为空");
    }
}

⛳ 解释:

  • throw new BusinessException(...):这里是真正扔出异常,让程序往上抛。
  • 这是运行时异常(RuntimeException),不需要throws,调用这个方法的人也不需要强制处理

🚀 场景二:方法可能连接数据库,查客户 → 声明可能抛异常(checked异常)

public Customer getCustomer(String custId) throws SQLException {
    Connection conn = dataSource.getConnection(); // 可能抛 SQLException
    ...
}

⛳ 解释:

  • throws SQLException是告诉别人:这个方法可能会抛数据库异常
  • 调用这个方法的地方必须 try-catch,或者继续throws抛出去

4.结合使用的例子(throw和throws都出现)

🚀 场景三:读取文件内容的方法

public String readFile(String path) throws IOException {
    FileReader reader = new FileReader(path); // 可能抛FileNotFoundException
    ...
    return content;
}

调用者必须这样写:

try {
    String content = readFile("data.txt");
} catch (IOException e) {
    System.out.println("读取文件失败:" + e.getMessage());
}

⛳ 总结:

  • throws IOException:声明可能发生异常(不处理会编译错误)
  • throw new IOException(...):在方法内部真正抛出错误对象

5.实际后端开发中的使用规律总结

异常类型

是否需要throws声明

常见场景

运行时异常(RuntimeException)

❌ 不强制

业务异常、空指针、非法状态等

检查型异常(IOException、SQLException等)

✅ 必须声明或 try-catch

文件操作、数据库连接、远程调用等

6.再帮你总结一下核心记忆点:

关键词

中文记忆法

关键点

throw

“抛出”

在代码块内部用,抛出异常对象

throws

“声明”

在方法签名上,告诉别人我可能抛异常

你可以记住一句话:

“throw 抛对象,throws 抛声明”

7.结合你目前学的内容再举一例(你的项目代码)

if (sysOffice == null){
    throw new BusinessException("jiesuan公司code不存在");
}
  • 这里你只写了throw,没有写throws,也不需要写,因为BusinessException是RuntimeException的子类。
  • 如果你抛的是IOException或SQLException,那你就必须throws它。

二、常见延伸思考:

throws只出现在方法定义的时候?

throws后必须要跟Exception的类型吗?

如果是的话,这个类型可以自定义吗?

这个throws其实在功能上一点用都没有,它只有一个用,告诉调用它的程序员,要在调用它的位置,写上try-catch,就这一个提示调用而已,对吗?

✅ throws是写在方法定义上,比如:

public void readFile() throws IOException {
    ...
}

throws后面必须跟一个或多个异常类的类型,比如:

throws IOException
throws IOException, SQLException

"throws后必须要跟一个exception类型吗?可以自定义吗?"

必须是Exception或它的子类!

  • 可以是系统的:IOException、SQLException
  • 也可以是你自定义的:比如 BusinessException、MyCustomException
public void saveData() throws BusinessException {
    ...
}

✅ 你说的第二点:

throws 的功能是"告诉调用者要 try-catch",其实没别的用,对吗?

✅ 你说得几乎完全正确!

它的核心作用的确就是:👉 "告诉调用者,我可能会抛出这些异常,你要么 try-catch,要么继续 throws 接着往上扔"。

这是Java的设计理念 —— "受检查异常(checked exception)必须显式处理”。

❗但注意:

只有非运行时异常(checked exception)必须throws和try-catch。

比如:

public void test() throws IOException {
    // 编译器会强制你 throws 或 try-catch
}

但像这种就不需要声明:

public void test() {
    throw new NullPointerException("空指针"); // 编译器不会管
}

✅ 总结你的理解版本(你可以这样记)

我理解的

是否正确

补充优化说

throws只能写在方法定义上

基本正确

是写在"方法或构造器定义上"

throws后必须是Exception类型

可以是系统的或自定义的

throws的功能就是告诉别人"你得 try-catch"

✅✅✅

本质就是编译器检查提示

throws本质上没别的作用

✅(语义上)

它不控制流程、也不抛异常,只是"声明"

🧠 一句话金句送你:

throw是真的"抛",throws是提前"告知"。

三、追问:

所以:

非检查异常基本都使用throw,而不需要try-catch,

检查异常基本都必须使用throws与try-catch结合的方式,对吗?

然后第二个问题是,在实际开发中,我该根据什么,或者说怎么判断一个区域的代码属于非检查异常还是检查异常,以及我该使用throw还是throws与try-catch的结合?

✅ 第一部分:你说的对吗?

❓你说:

非检查异常基本都使用throw,而不需要try-catch;

检查异常基本都必须使用throws与try-catch的方式。

非常正确!总结如下:

异常类型

是否必须try-catch

是否必须throws

常见写法

✅ 非检查异常(RuntimeException)

❌ 不需要

❌ 不需要

直接 throw new XxException()

✅ 检查异常(Exception 子类)

✅必须try或throws

✅ 必须

throws IOException + try-catch

这也是 Java 区分异常的核心设计哲学:

非检查异常表示"程序员你写错了",检查异常表示"你必须处理这个潜在的异常"。

✅ 第二部分:实战中怎么判断应该用哪种方式?

🎯[问题1]我怎么判断这段代码是否可能抛"检查异常"?

🛠 答案:靠工具提示 + 查看方法签名

比如你写下面这段代码时:

FileReader reader = new FileReader("hello.txt");

编译器会提示你:

Unhandled exception: java.io.FileNotFoundException

这就说明:

  1. FileReader的构造方法throws FileNotFoundException;
  2. 这是 检查异常(checked exception),你必须处理:
try {
    FileReader reader = new FileReader("hello.txt");
} catch (FileNotFoundException e) {
    ...
}

🎯【问题2】那我怎么判断某个异常是"检查"还是"非检查"?

✅ 答案:记住一个实用规则:

☆☆☆☆☆凡是继承自RuntimeException的,是非检查异常;其他都是检查异常☆☆☆☆☆ —— (太牛了这句话!)

实战中你不需要死记硬背,用IDE(比如 IntelliJ IDEA)可以直接看到类的继承结构:

举个例子:

java.lang.NullPointerException
↳ extends RuntimeException → ✅ 非检查异常
java.io.IOException
↳ extends Exception → ❌ 不是 RuntimeException → ✅ 检查异常

✅ 第三部分:开发中你该怎么选throw / throws?

这部分送你一张实战速查表:

情况类型

推荐使用

是否try-catch必须

你主动抛出业务异常

throw + 自定义异常(继承RuntimeException)

❌ 不需要

throw new BusinessException("参数非法")

使用Java API抛出检查异常的方法

throws + try-catch

✅ 必须

throws IOException, try FileReader

你写的工具类方法想抛出异常让别人处理

throws

声明

✅ 看情况

public void read() throws SQLException

系统程序错误,比如数组越界、空指针

直接throw

❌ 不需要

throw new NullPointerException()

💡 实战建议(经验分享):

✅ 常用套路1:业务异常都用RuntimeException

不声明throws,调用处也不用处理,统一交给全局异常处理器处理,比如:

if (user == null) {
    throw new BusinessException("用户不存在");
}

全局处理器:

@ExceptionHandler(BusinessException.class)
public Response handleBiz(BusinessException e) {
    return fail(e.getMessage());
}

常用套路2:调用第三方/系统API,就要try-catch或throws

比如文件、数据库、网络:

public void readFile(String path) throws IOException {
    FileReader reader = new FileReader(path);
}

✅ 常用套路3:如果你的方法是"中间层",你也可以用throws把异常继续往上传

public void processOrder(String id) throws SQLException {
    orderDao.save(id); // save() 方法 throws SQLException
}

让 Controller 再去处理,或者让上层统一处理。

✅ 总结你可以直接用的口诀:

🔹 throw抛对象,throws抛声明

🔹 RuntimeException不用管,Checked Exception必须处理

🔹 自己的业务用throw,自定义异常更清晰

🔹 调系统 API就用 throws或try-catch

全部评论

相关推荐

评论
点赞
2
分享

创作者周榜

更多
牛客网
牛客企业服务