JAVA-------异常(Exception)
一,区分异常和错误
在 Java 中,所有的异常都封装成了对象。它们的最高祖先是 java.lang.Throwable。
Throwable: 异常界的“老祖宗”。
Error (错误): 绝症。指 JVM 无法解决的严重问题(如:内存溢出 StackOverflowError)。程序员通常不处理它。
Exception (异常): 感冒发烧。程序运行中出现的不正常情况,可以通过代码修复。
1, 编译时异常 (Checked Exception): 编译器强制要求处理,不处理代码就跑不起来。
2,运行时异常 (RuntimeException): 代码逻辑错误,编译器不强制要求处理。
二,异常的分类
并非所有的异常都需要你立即处理。Java 根据异常发生的时机将其分为两类:
查型异常 (Checked Exception):
编译器强制要求处理。就像出门前必须检查是否带了钥匙。
运行时异常 (Unchecked/Runtime Exception):
编译器不强制,通常由代码逻辑错误引起。就像走在路上不小心踩到香蕉皮。
图表比较
| 特性 | 受检异常 (Checked) | 运行时异常 (Unchecked/Runtime) |
| 定义 | 编译时必须处理的异常。 | 编译时不强制要求处理。 |
| 发生时机 | 通常由外部环境引起(如文件不存在)。 | 通常由代码逻辑错误引起。 |
| 处理要求 | 必须 try-catch 或 throws,否则代码无法通过编译。 |
不强制要求,但好的习惯是提前检查代码逻辑。 |
| 常见例子 | IOException, SQLException。 |
NullPointerException (空指针), ArrayIndexOutOfBounds (越界)。 |
三,常见的异常
1. 编译时异常 (Checked Exception)
编译器在写代码时就会提醒你:“这里可能出事,你必须现在就写好应对方案!”
| 异常名称 | 触发场景 | 预防/解决办法 |
|
文件找不到 |
程序想读 D:/test.txt,但文件根本不存在。 |
检查路径是否正确,或先用 file.exists() 判断。 |
|
io异常 |
读写文件过程中突然断电、硬盘坏了或网络中断。 | 必须使用 try-catch 包围,并确保在 finally 中关闭资源。 |
|
找不到类 |
反射加载类(如驱动)时,在 ClassPath 里找不到对应的 .class 文件。 |
检查 Jar 包是否导入,类名拼写是否完全正确(包含包名)。 |
2. 运行时异常 (Unchecked Exception)
编译器不强制要求处理,它们通常是由于程序员逻辑不严谨导致的“低级错误”。
| 异常名称 | 触发场景 | 预防/解决办法 |
|
空指针异常 |
对 null 对象调用方法(如 String s=null; s.length();)。 |
最重要:操作前先做非空判断 if (obj != null)。 |
|
数组下标越界异常 |
数组长度为 3,你却访问 arr[3](下标从 0 开始,最大是 2)。 |
检查循环边界,确保索引在 0 到 length-1 之间。 |
|
算数运算异常 |
进行了不合法的数学运算(如 10 / 0)。 |
在做除法前,判断除数是否为 0。 |
|
类型转型异常 |
强行把“狗”转成“猫”(如 Animal a = new Dog(); Cat c = (Cat)a;)。 |
转型前使用 instanceof 进行类型检查。 |
|
数字格式化异常 |
把非数字字符串转成数字(如 Integer.parseInt("abc");)。 |
转换前通过正则表达式校验字符串是否为纯数字。 |
四,异常的处理方式
1,try-catch方式
一捕获三部曲:try - catch - finally
-
try: 包含可能出错的代码。 -
catch: 捕获具体的错误,并给出解决方案。 -
finally: 无论是否出错,一定执行的代码(用于关灯、关门、关闭资源)。
当运行 try错误时候-----(直接跳过当前位置进入到)-----catch 抛出异常
try {
int result = 10 / 0; // 这里会发生除零错误
//当上面这一行出现错误了 try 语句下面的代码不会运行直接跳到 catch语句
sout;
sout;
sout;
//sout 不会在运行直接跳过
//如过没有问题 则会跳过catch 进入到 finally语句中
} catch (ArithmeticException e) {
//抛出异常 抛出ArithmeticException 在控制台输出异常
//ArithmeticException 只能捕获算数异常 可以使用 顶级异常Exception
System.out.println("捕获到异常:除数不能为零!"); // 救场处理
} finally {
//无论上面有没有异常 finally 语句都会运行
System.out.println("不管出没出错,我都执行了。"); // 清理现场
}
2、throws方式
throws方法声明异常,交给上层处理方法不知道如何处理异常(比如工具类方法)
问题没有解决但是程序可以运行
import java.io.FileReader;
import java.io.FileNotFoundException;
import java.io.IOException;
// 定义一个读取文件的方法,声明抛出异常
public class ThrowsDemo {
// 该方法声明抛出 FileNotFoundException 和 IOException
public static void readFile(String filePath) throws FileNotFoundException, IOException {
// 这里没有用 try-catch 处理异常,而是直接抛出
FileReader reader = new FileReader(filePath);
int data = reader.read();
while (data != -1) {
System.out.print((char) data);
data = reader.read();
}
reader.close();
}
}
继续用 throws 抛给 JVM(不推荐,仅作示例)
public class Main {
// main方法继续抛出异常,最终由JVM处理(会直接崩溃并打印异常栈)
public static void main(String[] args) throws IOException {
ThrowsDemo.readFile("test.txt");
}
}
3,手动创建异常
new 一个对象 调用异常
throw new IllegalArgumentException("参数无效");
4,自定义异常
// 1. 自定义业务异常:继承 Exception(受检异常,必须显式处理)
public class InsufficientBalanceException extends Exception {
// 构造方法1:仅传递异常信息
public InsufficientBalanceException(String message) {
// 调用父类的构造方法,传递异常描述信息
super(message);
}
// 构造方法2:传递异常信息+原始异常(便于追踪异常链)
public InsufficientBalanceException(String message, Throwable cause) {
super(message, cause);
}
}
// 2. 可选:自定义非受检异常(继承 RuntimeException,无需强制处理)
public class InvalidOrderIdException extends RuntimeException {
public InvalidOrderIdException(String message) {
super(message);
}
}
手动创建异常 和自定义异常区别
| 维度 | 手动创建 (使用内置异常) | 自定义异常 (创建新类) |
| 本质 | 直接 new 一个 Java 自带的异常类。 |
先写一个类继承 Exception 或子类。 |
| 类名示例 | IllegalArgumentException。 |
UserPowerInsufficientException。 |
| 可读性 | 一般。只能通过错误信息(String)区分。 | 极高。看类名就知道发生了什么业务错误。 |
| 开发成本 | 极低。随拿随用。 | 略高。需要额外写代码定义类。 |
| 适用场景 | 通用的编程逻辑错误。 | 特定的业务规则逻辑错误。 |
异常练习
public class CoffeeMachineDemo {
/**
* 制作咖啡的方法
* @param waterAmount 水量(ml)
* @param personCount 分享人数
* @throws ArithmeticException 声明:如果人数为0,会抛出算数异常
*/
public static void makeCoffee(int waterAmount, int personCount) throws ArithmeticException {
System.out.println("【系统】启动加热程序...");
// 1. 【手动创建并抛出异常】:逻辑检查
if (waterAmount <= 0) {
// 我们手动发现水量不对,主动按下警报
throw new IllegalArgumentException("【报错】水箱没水了,当前水量:" + waterAmount);
}
// 2. 【自动触发异常】:JVM 发现错误
// 如果 personCount 为 0,JVM 会在此处自动抛出 ArithmeticException
int shareAmount = waterAmount / personCount;
System.out.println("【成功】每人分得咖啡: " + shareAmount + "ml");
}
public static void main(String[] args) {
// 3. 【捕获处理】:try-catch-finally 组合拳
try {
System.out.println(">> 用户按下按钮:准备制作咖啡...");
// --- 模拟调用(测试题目就在这里) ---
makeCoffee(300, 0);
System.out.println(">> 咖啡制作完成,请享用!");
} catch (IllegalArgumentException e) {
// 捕获【手动】抛出的异常
System.err.println("【处理警报】" + e.getMessage());
} catch (ArithmeticException e) {
// 捕获【自动】触发的异常
System.err.println("【处理故障】不能分给 0 个人!请检查人数输入。");
} finally {
// 无论出不出错,最后都要关闭电源
System.out.println("【系统】咖啡机进入待机模式,电源已切断。");
}
}
}
更多推荐




所有评论(0)