前言:关于“谁来背锅”的哲学讨论

坐标:图书馆 2 楼靠窗位(今天终于抢到了有插座的位置!)

状态:冰美式特浓,脑细胞正在高速运转。

碎碎念: 兄弟们,今天写代码的时候,我陷入了深深的思考。 有时候程序出错了,我是该直接在那儿处理掉呢,还是假装没看见,把球踢给调用我的那个人?

这在 Java 里其实就是 throwthrows 的博弈。学长告诉我:“写程序就像在寝室打扫卫生,有的垃圾你自己随手捡了(try-catch),有的垃圾你得贴个告示告诉室友‘这儿有垃圾,谁最后走谁倒’(throws)。”

今天咱就来扒一扒这对“甩锅”兄弟的底细,看看在 Java 的异常战场上,它们到底是怎么配合演戏的!

🚀 目录

  1. 一眼定乾坤:实干家 vs 预言家

  2. throw:亲手扔出的“手榴弹”

    • 2.1 什么时候主动扔异常?

    • 2.2 它的语法潜规则

  3. throws:优雅的“免责声明”

    • 3.1 为什么要有 throws?

    • 3.2 运行时异常 vs 编译时异常的不同态度

  4. 核心对撞:一张表教你做人

  5. 深度思考:甩锅的终点在哪里?

  6. 面试高频考点演练

  7. 结语:优秀的程序员懂得适时甩锅

1. 一眼定乾坤:实干家 vs 预言家

在 Java 世界里,你可以通过名字后面的那个 s 来快速区分它们:

  • throw (实干家):它是一个动作,表示“现在就要抛出一个异常”。

  • throws (预言家):它是一个声明,表示“我这儿可能会出现异常,大家小心”。

大学生比喻

  • throw 就像你亲手把一个挂科的消息发给老妈。

  • throws 就像你在成绩单信封上贴个条子:“内有挂科通知,打开前请自备速效救心丸”

2. throw:亲手扔出的“手榴弹”

throw 关键字后面跟着的是一个具体的异常对象

2.1 什么时候主动扔异常?

通常是在逻辑判断不通过的时候。比如你写一个“发工资”的方法,如果金额是负数,这就不符合常理,你得抛个异常:

public void paySalary(double money) {
    if (money < 0) {
        // 主动制造并抛出一个异常,逻辑到此中断
        throw new IllegalArgumentException("工资居然是负数?老板你良心呢!");
    }
    System.out.println("成功发放工资:" + money);
}

2.2 它的语法潜规则

  • throw 必须写在方法体内部。

  • 每次只能抛出一个具体的异常实例。

  • 只要 throw 一执行,方法剩下的代码就再也不会跑了(除非它在 try 块里且有 finally)。

3. throws:优雅的“免责声明”

throws 写在方法头(参数列表后面),后面跟着的是异常类名

3.1 为什么要有 throws?

Java 编译器非常严谨。如果你在方法里干了一些“危险动作”(比如读文件),编译器会强迫你处理异常。如果你不想在方法里写繁琐的 try-catch,你就得用 throws 告诉上级:“我这儿可能有炸弹,接球的人你自己看着办。”

3.2 两种异常的不同待遇

  • 运行时异常 (RuntimeException):你想声明就声明,不声明编译器也不管你。

  • 编译时异常 (Checked Exception)必须声明!如果不声明又不捕获,代码根本编译不过去。

// 这是一个危险的方法,它声明了可能会抛出 FileNotFoundException
public void readFile(String path) throws FileNotFoundException {
    // 这里并没有 try-catch,因为我用 throws 把锅甩出去了
    FileInputStream fis = new FileInputStream(path);
}

4. 核心对撞:一张表教你做人

特征

throw

throws

位置

方法体内

方法名后面,参数列表后

后面跟的是...

异常对象 (new XXXException())

异常类型 (XXXException.class)

数量

只能抛出一个对象

可以声明多个类型(逗号隔开)

作用

主动制造异常,结束当前方法

提醒调用者处理异常,是一种免责声明

性质

实际的动作(抛球)

可能的危险预告(看球)

5. 深度思考:甩锅的终点在哪里?

很多同学问我:“如果我也 throws,我上级也 throws,那最后这个锅谁背?”

答案是:JVM(虚拟机)。 如果异常一直向上甩,最后没人处理,JVM 就会无奈地站出来,把异常信息打印在控制台(也就是咱们最怕的红字),然后直接强制关掉你的程序

所以,甩锅虽爽,但终究得有人接。 优秀的程序员会在最合适的地方(通常是 Controller 层或 UI 交互层)通过 try-catch 把锅接住,给用户一个体面的提示。

6. 面试高频考点演练

Q1:throw 后面的代码还会执行吗? 答案:除了在 finally 块里,否则 throw 后面的代码都是 Unreachable(不可达),编译器会报错。

Q2:如果重写(Override)的方法,父类没写 throws,子类能写吗? 答案不能!子类抛出的编译时异常不能大于父类。

  • 比喻:老爸说这事儿没危险,你不能跳出来说这事儿要人命。

Q3:throw null 会发生什么? 答案:会触发 NullPointerException。因为 throw 后面必须是一个有效的异常对象。

7. 结语

写完这篇日记,我终于把项目里那些乱七八糟的 try-catch 清理掉了一部分。有些该甩给全局异常处理器处理的锅,果断用 throws 甩了出去。

作为大学生的我们:

  • 要敢于 throw(当数据不对,要有拒绝的勇气)。

  • 要学会 throws(声明风险,保护自己)。

  • 但最后一定要有 try-catch(负责到底,才是真爷们)。

如果你也被这俩“兄弟”绕晕过,点个赞支持一下!下期聊聊checked exception和runtime exception

更多推荐