《Java 100 天进阶之路》第6篇:Java异常有哪几种
第6篇:Java异常有哪几种
📌 系列导航:《Java 100 天进阶之路》完整目录 |
⬅️ 上一篇:第5篇:装箱和拆箱 |
➡️ 下一篇:第7篇:Java面向对象简介
一、核心知识点
- 异常体系分类:检查型异常(Checked Exception)、运行时异常(Runtime Exception)、错误(Error)
- 异常处理关键字:
try、catch、finally、throws、throw - 常见异常类:
NullPointerException、ArrayIndexOutOfBoundsException、IOException、SQLException等 - 异常处理规范和最佳实践
二、通俗讲解(1分钟开心学)
1. 异常是什么?
程序运行时会遇到各种意外情况,比如:
- 用户输入的年龄是-5岁(不合理)
- 要读取的文件不存在
- 网络突然断开
- 数组下标越界
这些意外就是“异常”。Java 把它们分成了三大类:
2. 三大异常类型
| 类型 | 英文名 | 特点 | 例子 |
|---|---|---|---|
| 检查型异常 | Checked Exception | 编译器强制处理(要么 try-catch,要么 throws),代表可以预见的、外部环境引起的问题 | IOException(文件找不到)、SQLException(数据库连接失败) |
| 运行时异常 | Runtime Exception | 不强制处理,通常由程序逻辑错误引起。出现这种异常说明代码写错了,应该修改代码而不是捕获 | NullPointerException(空指针)、ArrayIndexOutOfBoundsException(数组越界)、ArithmeticException(除以零) |
| 错误 | Error | 不是程序能处理的,JVM 内部严重问题 | OutOfMemoryError(内存溢出)、StackOverflowError(栈溢出) |
3. 异常处理的关键字
try:放可能出错的代码catch:捕获特定异常并处理finally:无论是否发生异常,都会执行的代码(用于释放资源)throw:手动抛出异常对象throws:声明方法可能抛出的异常,交给调用者处理
生活类比:
检查型异常就像你出门前天气预报说有雨。你必须带伞(处理异常),否则会被淋湿。
运行时异常就像你在晴天突然踩到香蕉皮滑倒。这通常是你自己不小心(代码写错),而不是环境问题。
错误就像突然地震了,你个人无能为力,只能靠整个系统(JVM)处理。
三、实操代码案例 + 场景说明
场景:从文件读取用户配置,如果文件不存在则尝试使用默认配置。
1. 检查型异常处理(必须处理)
import java.io.*;
public class CheckedExceptionDemo {
public static void main(String[] args) {
// 方式一:try-catch 捕获处理
try {
FileReader fr = new FileReader("config.txt");
BufferedReader br = new BufferedReader(fr);
String line = br.readLine();
System.out.println("配置内容:" + line);
br.close();
} catch (FileNotFoundException e) {
System.out.println("文件不存在,使用默认配置");
} catch (IOException e) {
System.out.println("读取文件出错:" + e.getMessage());
}
// 方式二:throws 向上抛出(交给调用者)
// 适用于方法本身无法处理异常的情况
}
// 声明 throws,表示调用者必须处理
public void readConfig() throws IOException {
FileReader fr = new FileReader("config.txt");
// ...
}
}
2. 运行时异常(不强制处理,但最好修复代码)
public class RuntimeExceptionDemo {
public static void main(String[] args) {
// 错误写法:运行时异常不处理会崩溃
int[] arr = {1, 2, 3};
// System.out.println(arr[3]); // 运行会抛 ArrayIndexOutOfBoundsException
// 正确做法:修复代码,而不是捕获
if (args.length > 0) {
System.out.println(args[0]);
}
// 如果确实需要捕获(比如防御性编程),也可以,但不推荐
try {
int a = 10 / 0;
} catch (ArithmeticException e) {
System.out.println("除数不能为0,已处理");
}
}
}
3. finally 与 try-with-resources
public class FinallyDemo {
public static void main(String[] args) {
// 传统方式:手动关闭资源
FileInputStream fis = null;
try {
fis = new FileInputStream("data.txt");
int data = fis.read();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (fis != null) {
try {
fis.close(); // 关闭也可能抛异常
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 优雅方式:try-with-resources(JDK7+)
try (FileInputStream fis2 = new FileInputStream("data.txt")) {
int data = fis2.read();
} catch (IOException e) {
e.printStackTrace();
} // 自动关闭,不需要 finally
}
}
4. 自定义异常
// 自定义检查型异常
class AgeInvalidException extends Exception {
public AgeInvalidException(String message) {
super(message);
}
}
public class CustomExceptionDemo {
public static void checkAge(int age) throws AgeInvalidException {
if (age < 0 || age > 150) {
throw new AgeInvalidException("年龄非法:" + age);
}
System.out.println("年龄合法");
}
public static void main(String[] args) {
try {
checkAge(-5);
} catch (AgeInvalidException e) {
System.out.println("捕获异常:" + e.getMessage());
}
}
}
四、避坑要点
| 错误/误区 | 后果 | 正确做法 |
|---|---|---|
| 捕获异常后什么都不做(空 catch) | 问题被掩盖,难以排查 | 至少记录日志或打印堆栈 |
catch 的顺序把父类放在子类前面 |
子类异常永远捕获不到 | 子类在前,父类在后 |
在 finally 块中 return |
会覆盖 try 或 catch 中的 return |
避免在 finally 中 return |
| 用异常控制正常业务流程 | 性能极差 | 用 if-else 判断 |
throws 声明了检查型异常却从不抛出 |
造成调用者无意义的处理 | 只声明真正会抛出的异常 |
五、面试高频考点
Q1:检查型异常和运行时异常的区别?
检查型异常编译器强制处理(
try-catch或throws),代表可恢复的外部错误(如文件不存在)。运行时异常不强制处理,代表编程错误(如空指针、越界)。Error是 JVM 内部错误。
Q2:throw 和 throws 的区别?
throw用于实际抛出异常对象(在方法体内);throws写在方法签名后,声明该方法可能抛出的异常类型。
Q3:finally 块一定会执行吗?
不一定。如果
try或catch中调用了System.exit(),或者 JVM 崩溃,finally不会执行。
Q4:try-with-resources 的原理?
实现了
AutoCloseable接口的资源可以在try括号中声明,try结束后自动调用close()。编译器会生成finally块并处理异常抑制(addSuppressed)。
六、练习题
- 简答:写出至少5种运行时异常的名称。
- 编程:编写一个方法
int divide(int a, int b),当b==0时抛出自定义运行时异常DivideByZeroException。 - 代码改错:指出下面代码的问题并修正。
try { int[] arr = new int[5]; System.out.println(arr[5]); } catch (Exception e) { e.printStackTrace(); } catch (ArrayIndexOutOfBoundsException e) { System.out.println("越界"); }
📊 你的学习进度
- 当前:第6篇 / 共44篇 · 第二阶段:核心语法与面向对象(第5~20篇)
- ✅ 已完成:第1~5篇
- 📖 正在学:第6篇
- ⏳ 待学习:第7~44篇
👉 📚 完整目录 & 学习指南 | 🔥 订阅本专栏,不错过每一篇
💡 本专栏每篇都包含:避坑表 + 面试高频考点 + 练习题。每天30分钟,100天拿offer!
👉 下一篇预告
《Java面向对象简介》
内容简介:面向对象三大特征(封装、继承、多态)是什么?类和对象有什么区别?
💡 学完这篇,你将理解为什么 Java 是面向对象的语言,并能用 OOP 思想设计简单程序。
📌 《Java 100 天进阶之路 | 从入门到上岗就业》 每天一篇,建议收藏 + 关注,一起100天拿offer!
👉 点击关注我,更新后第一时间收到推送!
更多推荐


所有评论(0)