目录
- 一、简要介绍
- 二、编译时异常
-
- [1. IOException(输入输出异常)](#1. IOException(输入输出异常))
- 2、FileNotFoundException(文件未找到异常)
- 3、SQLException(数据库异常)
- 4、ClassNotFoundException(类未找到异常)
- 5、InterruptedException(线程中断异常)
- 三、运行时异常
-
- [1、 NullPointerException(空指针异常)](#1、 NullPointerException(空指针异常))
- 2、ArrayIndexOutOfBoundsException(数组越界异常)
- 3、ClassCastException(类型转换异常)
- [4、 IllegalArgumentException(非法参数异常)](#4、 IllegalArgumentException(非法参数异常))
- 5、NumberFormatException(数字格式异常)
一、简要介绍
java
// Java异常体系
Throwable
├── Error (错误,如内存溢出)
├── Exception (异常)
├── RuntimeException (运行时异常 - unchecked)
└── 其他Exception (编译时异常 - checked)

简单理解:当你把代码写出来的时候,编译器有红色波浪线出现的时候为编译时异常,运行时出现的异常为运行时异常。
二、编译时异常
1. IOException(输入输出异常)
java
import java.io.*;
public class IOExceptionExample {
public void readFileContent(String filePath) {
try {
// 文件读取操作可能抛出IOException
FileReader reader = new FileReader(filePath);
BufferedReader br = new BufferedReader(reader);
String line;
while ((line = br.readLine()) != null) { // 读取时可能发生IO异常
System.out.println(line);
}
br.close();
} catch (IOException e) { // 必须捕获或声明抛出
System.out.println("文件读取失败: " + e.getMessage());
e.printStackTrace();
}
}
// 或者在方法声明中抛出
public void writeToFile(String filePath, String content) throws IOException {
FileWriter writer = new FileWriter(filePath);
writer.write(content); // 写入时可能发生IO异常
writer.close();
}
}
出现的情况:
文件读取/写入时磁盘故障
网络传输中断
流操作异常
文件权限不足
2、FileNotFoundException(文件未找到异常)
java
import java.io.*;
public class FileNotFoundExceptionExample {
public void processFile(String filename) {
try {
// 尝试打开不存在的文件
FileInputStream fis = new FileInputStream(filename); // 可能抛出FileNotFoundException
// 处理文件...
fis.close();
} catch (FileNotFoundException e) {
System.out.println("文件不存在: " + filename);
// 创建新文件或提示用户
createNewFile(filename);
} catch (IOException e) {
System.out.println("IO错误: " + e.getMessage());
}
}
private void createNewFile(String filename) {
try {
File file = new File(filename);
if (file.createNewFile()) {
System.out.println("创建新文件: " + filename);
}
} catch (IOException e) {
System.out.println("创建文件失败: " + e.getMessage());
}
}
}
文件路径错误
文件名拼写错误
文件被移动或删除
路径权限限制
3、SQLException(数据库异常)
java
import java.sql.*;
public class SQLExceptionExample {
private static final String URL = "jdbc:mysql://localhost:3306/test";
private static final String USER = "root";
private static final String PASSWORD = "password";
public void queryUserData(int userId) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// 数据库连接可能失败
conn = DriverManager.getConnection(URL, USER, PASSWORD);
// SQL执行可能失败
pstmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?");
pstmt.setInt(1, userId);
rs = pstmt.executeQuery(); // 可能抛出SQLException
while (rs.next()) {
System.out.println("用户: " + rs.getString("username"));
}
} catch (SQLException e) {
System.out.println("数据库操作失败:");
System.out.println("错误码: " + e.getErrorCode());
System.out.println("SQL状态: " + e.getSQLState());
System.out.println("错误信息: " + e.getMessage());
} finally {
// 关闭资源
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
if (conn != null) conn.close();
} catch (SQLException e) {
System.out.println("关闭连接失败: " + e.getMessage());
}
}
}
}
数据库连接失败
SQL语法错误
表或列不存在
违反约束(如主键重复)
事务回滚
4、ClassNotFoundException(类未找到异常)
java
public class ClassNotFoundExceptionExample {
public void loadClassDynamically(String className) {
try {
// 动态加载类
Class<?> clazz = Class.forName(className); // 可能抛出ClassNotFoundException
System.out.println("成功加载类: " + clazz.getName());
// 创建实例
Object instance = clazz.newInstance();
System.out.println("创建实例: " + instance);
} catch (ClassNotFoundException e) {
System.out.println("类未找到: " + className);
System.out.println("请检查:");
System.out.println("1. 类名拼写是否正确");
System.out.println("2. 类是否在classpath中");
System.out.println("3. 依赖包是否已添加");
} catch (InstantiationException | IllegalAccessException e) {
System.out.println("实例化失败: " + e.getMessage());
}
}
// 实际应用场景:插件系统
public void loadPlugin(String pluginClassName) {
try {
Class<?> pluginClass = Class.forName(pluginClassName);
Plugin plugin = (Plugin) pluginClass.newInstance();
plugin.execute();
} catch (ClassNotFoundException e) {
System.out.println("插件类未找到: " + pluginClassName);
} catch (Exception e) {
System.out.println("插件加载失败: " + e.getMessage());
}
}
}
interface Plugin {
void execute();
}
动态类加载时类路径错误
缺少必要的JAR包
类名拼写错误
类文件被删除或损坏
5、InterruptedException(线程中断异常)
java
public class InterruptedExceptionExample {
public void timeConsumingTask() {
Thread workerThread = new Thread(() -> {
try {
System.out.println("任务开始执行...");
// 模拟耗时操作
for (int i = 0; i < 10; i++) {
System.out.println("处理第 " + i + " 个步骤");
// 检查线程中断状态
if (Thread.currentThread().isInterrupted()) {
System.out.println("任务被中断,开始清理...");
return;
}
// 线程睡眠 - 可能被中断
Thread.sleep(1000); // 可能抛出InterruptedException
}
System.out.println("任务完成");
} catch (InterruptedException e) {
// 线程在sleep/wait/join时被中断
System.out.println("任务被中断,恢复中断状态");
Thread.currentThread().interrupt(); // 恢复中断状态
// 执行清理操作
cleanup();
}
});
workerThread.start();
// 3秒后中断任务
try {
Thread.sleep(3000);
workerThread.interrupt(); // 中断线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void cleanup() {
System.out.println("执行清理操作...");
// 释放资源、回滚操作等
}
// 实际应用:超时控制
public void executeWithTimeout(Runnable task, long timeoutMs) {
Thread taskThread = new Thread(task);
taskThread.start();
try {
taskThread.join(timeoutMs); // 等待任务完成或超时
if (taskThread.isAlive()) {
System.out.println("任务超时,中断执行");
taskThread.interrupt();
}
} catch (InterruptedException e) {
System.out.println("等待被中断");
taskThread.interrupt();
}
}
}
线程在sleep()时被中断
线程在wait()时被中断
线程在join()时被中断
执行超时控制
优雅停止线程

三、运行时异常
1、 NullPointerException(空指针异常)
java
public class NullPointerExceptionExample {
public void commonNPEscenarios() {
// 场景1:调用null对象的方法
String str = null;
System.out.println(str.length()); // NullPointerException
// 场景2:访问null数组元素
int[] arr = null;
System.out.println(arr[0]); // NullPointerException
// 场景3:自动拆箱null
Integer number = null;
int value = number; // NullPointerException(自动拆箱)
}
// 实际开发中的防御性编程
public void processUser(User user) {
// ❌ 错误做法
if (user.getName().equals("admin")) { // 如果user或user.getName()为null,NPE
// ...
}
// ✅ 正确做法1:提前判空
if (user != null && user.getName() != null
&& user.getName().equals("admin")) {
// ...
}
// ✅ 正确做法2:使用Objects.requireNonNull
Objects.requireNonNull(user, "用户对象不能为空");
Objects.requireNonNull(user.getName(), "用户名不能为空");
// ✅ 正确做法3:使用Optional(Java 8+)
Optional.ofNullable(user)
.map(User::getName)
.filter(name -> name.equals("admin"))
.ifPresent(name -> System.out.println("管理员用户"));
}
// 深度嵌套对象的安全访问
public void safeDeepAccess(User user) {
// ❌ 危险的多层调用
String city = user.getAddress().getCity().getName(); // 随时可能NPE
// ✅ 安全的多层访问
String safeCity = Optional.ofNullable(user)
.map(User::getAddress)
.map(Address::getCity)
.map(City::getName)
.orElse("未知城市");
System.out.println("城市: " + safeCity);
}
}
class User {
private String name;
private Address address;
// getters/setters...
}
class Address {
private City city;
// getters/setters...
}
class City {
private String name;
// getters/setters...
}
调用null对象的方法或属性
数组为null时访问元素
集合操作中的null元素
链式调用中的中间对象为null
2、ArrayIndexOutOfBoundsException(数组越界异常)
java
public class ArrayIndexExceptionExample {
public void arrayOperations() {
// 场景1:访问超出长度的索引
int[] arr = {1, 2, 3};
System.out.println(arr[3]); // 数组越界,有效索引:0-2
// 场景2:循环边界错误
for (int i = 0; i <= arr.length; i++) { // 应为 i < arr.length
System.out.println(arr[i]); // 最后一次循环会越界
}
// 场景3:负数索引
System.out.println(arr[-1]); // 数组越界
}
// 安全访问数组
public void safeArrayAccess(int[] arr, int index) {
// ✅ 方法1:检查边界
if (index >= 0 && index < arr.length) {
System.out.println("元素: " + arr[index]);
} else {
System.out.println("索引 " + index + " 越界,数组长度: " + arr.length);
}
// ✅ 方法2:使用try-catch
try {
System.out.println("元素: " + arr[index]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组访问越界: " + e.getMessage());
// 返回默认值或抛出业务异常
}
}
// 实际应用:矩阵操作
public void matrixOperation(int[][] matrix, int row, int col) {
// 安全访问二维数组
if (row >= 0 && row < matrix.length
&& col >= 0 && col < matrix[row].length) {
System.out.println("Matrix[" + row + "][" + col + "] = " + matrix[row][col]);
} else {
throw new IllegalArgumentException("矩阵索引越界");
}
}
// 使用增强for循环避免越界
public void safeIteration() {
String[] names = {"Alice", "Bob", "Charlie"};
// ✅ 安全的迭代方式
for (String name : names) {
System.out.println(name); // 不会越界
}
// 如果需要索引
for (int i = 0; i < names.length; i++) {
System.out.println(i + ": " + names[i]);
}
}
}
访问超出数组长度的索引
循环条件错误导致索引超限
使用负数索引
多维数组访问越界
3、ClassCastException(类型转换异常)
java
public class ClassCastExceptionExample {
public void typeCastingIssues() {
// 场景1:错误的向下转型
Object obj = "Hello World";
Integer number = (Integer) obj; // ClassCastException: String不能转为Integer
// 场景2:集合中的错误类型
List list = new ArrayList();
list.add("字符串");
list.add(123); // 自动装箱为Integer
for (Object item : list) {
String str = (String) item; // 当item是Integer时抛出异常
}
}
// 安全的类型检查和转换
public void safeTypeCasting(Object obj) {
// ✅ 方法1:使用instanceof检查
if (obj instanceof String) {
String str = (String) obj;
System.out.println("字符串长度: " + str.length());
} else if (obj instanceof Integer) {
Integer num = (Integer) obj;
System.out.println("数值: " + num);
} else {
System.out.println("不支持的类型: " + obj.getClass());
}
// ✅ 方法2:Java 16+的模式匹配
if (obj instanceof String str) {
System.out.println("字符串: " + str);
}
}
// 泛型集合的类型安全
public void genericCollectionSafety() {
// ❌ 原始类型(危险)
List rawList = new ArrayList();
rawList.add("test");
rawList.add(123); // 允许添加不同类型
// ✅ 使用泛型(安全)
List<String> stringList = new ArrayList<>();
stringList.add("test");
// stringList.add(123); // 编译错误,类型安全
// 类型安全的转换
List<Object> mixedList = new ArrayList<>();
mixedList.add("Hello");
mixedList.add(42);
for (Object item : mixedList) {
if (item instanceof String) {
processString((String) item);
} else if (item instanceof Integer) {
processInteger((Integer) item);
}
}
}
// 实际应用:多态处理
public void handleAnimals(List<Animal> animals) {
for (Animal animal : animals) {
animal.makeSound();
// 安全的特定类型处理
if (animal instanceof Dog dog) {
dog.fetch(); // Dog特有方法
} else if (animal instanceof Cat cat) {
cat.climb(); // Cat特有方法
}
}
}
}
class Animal {
void makeSound() {
System.out.println("动物叫声");
}
}
class Dog extends Animal {
@Override void makeSound() {
System.out.println("汪汪");
}
void fetch() {
System.out.println("捡球");
}
}
class Cat extends Animal {
@Override void makeSound() {
System.out.println("喵喵");
}
void climb() {
System.out.println("爬树");
}
}
错误的向下转型
原始类型集合的类型混淆
反射创建对象后错误转型
多态对象的错误类型判断
4、 IllegalArgumentException(非法参数异常)
java
public class IllegalArgumentExceptionExample {
// 参数验证的典型应用
public void setAge(int age) {
// ✅ 防御性编程:验证参数
if (age < 0 || age > 150) {
throw new IllegalArgumentException(
"年龄必须在0-150之间,当前值: " + age);
}
this.age = age;
}
public void createUser(String username, String email) {
// 验证用户名
if (username == null || username.trim().isEmpty()) {
throw new IllegalArgumentException("用户名不能为空");
}
if (username.length() < 3 || username.length() > 20) {
throw new IllegalArgumentException(
"用户名长度必须在3-20之间");
}
// 验证邮箱格式
if (email == null || !email.contains("@")) {
throw new IllegalArgumentException("邮箱格式不正确");
}
// 创建用户逻辑...
System.out.println("创建用户: " + username);
}
// 集合操作的参数验证
public void processList(List<String> list, int start, int end) {
Objects.requireNonNull(list, "列表不能为空");
if (start < 0 || end > list.size() || start > end) {
throw new IllegalArgumentException(
String.format("索引范围无效: start=%d, end=%d, size=%d",
start, end, list.size()));
}
// 处理子列表
List<String> subList = list.subList(start, end);
// ...
}
// 使用自定义异常提供更详细信息
public void validateOrder(Order order) {
if (order == null) {
throw new IllegalArgumentException("订单不能为空");
}
if (order.getItems() == null || order.getItems().isEmpty()) {
throw new EmptyOrderException("订单商品不能为空");
}
if (order.getTotalAmount() <= 0) {
throw new InvalidAmountException("订单金额必须大于0");
}
// 更多验证...
}
}
// 自定义业务异常
class EmptyOrderException extends IllegalArgumentException {
public EmptyOrderException(String message) {
super(message);
}
}
class InvalidAmountException extends IllegalArgumentException {
public InvalidAmountException(String message) {
super(message);
}
}
方法参数不符合预期范围
参数为null或空字符串
参数格式不正确
业务规则验证失败
5、NumberFormatException(数字格式异常)
java
public class NumberFormatExceptionExample {
public void parseNumbers() {
// 场景1:解析非数字字符串
String str1 = "abc123";
int num1 = Integer.parseInt(str1); // NumberFormatException
// 场景2:空字符串或null
String str2 = "";
int num2 = Integer.parseInt(str2); // NumberFormatException
// 场景3:包含特殊字符
String str3 = "123.45";
int num3 = Integer.parseInt(str3); // NumberFormatException(有小数点)
// 场景4:超出范围
String str4 = "99999999999999999999";
long num4 = Long.parseLong(str4); // 可能超出范围
}
// 安全的数字解析
public Integer safeParseInt(String str) {
// ✅ 方法1:try-catch
try {
return Integer.parseInt(str);
} catch (NumberFormatException e) {
System.out.println("数字格式错误: " + str);
return null; // 或返回默认值
}
}
public Integer safeParseIntWithDefault(String str, Integer defaultValue) {
try {
return Integer.parseInt(str);
} catch (NumberFormatException e) {
return defaultValue;
}
}
// ✅ 方法2:使用正则验证
public boolean isValidInteger(String str) {
if (str == null || str.trim().isEmpty()) {
return false;
}
// 允许正负号开头
String pattern = "^[-+]?\\d+$";
return str.matches(pattern);
}
public Integer parseWithValidation(String str) {
if (!isValidInteger(str)) {
throw new IllegalArgumentException("无效的整数格式: " + str);
}
try {
return Integer.valueOf(str);
} catch (NumberFormatException e) {
// 理论上不会到达这里,但作为额外保护
throw new IllegalArgumentException("数字超出范围: " + str);
}
}
// 实际应用:处理用户输入
public void processUserInput(String input) {
// 清理输入
String cleaned = input.trim();
// 多种解析尝试
Number number = null;
try {
// 先尝试整数
number = Integer.parseInt(cleaned);
} catch (NumberFormatException e1) {
try {
// 再尝试浮点数
number = Double.parseDouble(cleaned);
} catch (NumberFormatException e2) {
try {
// 尝试科学计数法
number = new java.math.BigDecimal(cleaned);
} catch (NumberFormatException e3) {
System.out.println("无法解析的数字: " + input);
return;
}
}
}
System.out.println("解析成功: " + number);
}
// 使用Scanner进行安全解析
public void safeParseWithScanner(String input) {
Scanner scanner = new Scanner(input);
if (scanner.hasNextInt()) {
int value = scanner.nextInt();
System.out.println("整数: " + value);
} else if (scanner.hasNextDouble()) {
double value = scanner.nextDouble();
System.out.println("浮点数: " + value);
} else {
System.out.println("不是有效数字: " + input);
}
scanner.close();
}
}
将非数字字符串转为数字类型
字符串包含非数字字符
数字格式不符合预期(如包含逗号、小数点等)
数字超出类型的范围
