Java常见异常全面梳理(含分类+含义+典型场景)
Java 异常体系核心分为 运行时异常(RuntimeException,非受检) 和 编译时异常(Checked Exception 受检),前者编译期无需强制捕获,由程序逻辑错误导致;后者编译期必须显式捕获/抛出,由外部环境(如IO、网络、输入)异常导致。此外,还有错误(Error) 属于JVM层面严重问题,通常无需程序处理。
区分「运行时异常(预防为主)、受检异常(强制处理)、JVM错误(提前规避)」

一、运行时异常(RuntimeException)—— 逻辑错误主导,预防优先,捕获兜底
继承自java.lang.RuntimeException,编译期无需强制处理,多由代码逻辑不严谨导致,核心处理原则是通过严谨的代码逻辑从根源避免,仅对无法预防的场景做捕获兜底。
1. NullPointerException(NPE)—— 开发最高频异常
- 核心含义:调用空对象的方法/属性、对空对象执行集合/数组操作,或自动拆箱空包装类
- 典型场景:
Object obj = null; obj.toString();、Integer num = null; int n = num;、方法返回null未判空直接使用 - 标准处理方式(按优雅度排序,从基础到高级)
- 基础方案:显式判空,对所有可能为null的对象执行非空校验;
- 优雅方案:Java 8+
Optional类,包装可能为null的对象,避免手动判空; - 校验方案:使用
Objects.requireNonNull()做参数/对象非空校验,快速定位空指针源头; - 开发规范:方法返回值尽量返回空集合/空对象(如
Collections.emptyList()),而非null,减少调用方判空成本。
- 核心代码示例
// 1. 显式判空
Object obj = getObj();
if (obj != null) {
obj.toString();
}
// 2. Optional优雅处理(推荐,无嵌套判空)
Optional.ofNullable(getObj()).ifPresent(o -> o.toString()); // 仅当非空时执行
String res = Optional.ofNullable(getStr()).orElse("默认值"); // 空则返回默认值
// 3. 非空校验(参数/方法内对象,快速定位问题)
public void doWork(User user) {
Objects.requireNonNull(user, "用户对象不能为空");
Objects.requireNonNull(user.getName(), "用户名不能为空");
}
- 避坑点:切勿仅用
if (obj != null)做多层嵌套判空(会导致代码臃肿),优先使用Optional。
2. ArrayIndexOutOfBoundsException —— 数组操作专属
- 核心含义:访问数组的索引超出有效范围(索引<0 或 索引>=数组长度)
- 典型场景:
int[] arr = new int[3]; arr[3] = 10;、循环遍历数组时条件写为i <= arr.length - 标准处理方式
- 核心原则:遍历数组始终以
arr.length为边界,循环条件用i < arr.length; - 根源规避:使用增强for循环遍历数组,无需手动操作索引,从源头避免越界;
- 前置校验:手动操作索引时,先校验索引合法性(
index >= 0 && index < arr.length)。
- 核心原则:遍历数组始终以
- 核心代码示例
int[] arr = {1,2,3};
// 1. 增强for循环(推荐,无索引操作)
for (int num : arr) {
System.out.println(num);
}
// 2. 手动索引操作(前置校验)
int index = 3;
if (index >= 0 && index < arr.length) {
System.out.println(arr[index]);
} else {
System.err.println("索引越界,合法索引0-" + (arr.length-1));
}
3. IndexOutOfBoundsException(含子类StringIndexOutOfBoundsException)
- 核心含义:访问集合/字符串的索引超出有效范围,是数组越界的「集合/字符串版」
- 典型场景:
List<String> list = new ArrayList<>(); list.get(0);、"java".substring(5) - 标准处理方式
- 集合操作:遍历用增强for循环,手动获取元素前校验
index < list.size()+集合非空(!list.isEmpty()); - 字符串操作:截取/获取字符前校验
index < str.length()+字符串非空(!str.isBlank()); - 工具辅助:使用
org.apache.commons.lang3.StringUtils/CollectionUtils,避免原生方法的越界问题。
- 集合操作:遍历用增强for循环,手动获取元素前校验
- 核心代码示例
List<String> list = Arrays.asList("a", "b");
String str = "java";
int index = 4;
// 集合安全获取
if (!CollectionUtils.isEmpty(list) && index < list.size()) {
System.out.println(list.get(index));
}
// 字符串安全截取(Apache工具类,越界会返回空/原字符串,无异常)
String sub = StringUtils.substring(str, 0, index);
4. ClassCastException —— 类型转换高频异常
- 核心含义:将对象强制转换为其实际运行时类型并非所属的类/接口(无继承/实现关系)
- 典型场景:
Object obj = new Integer(10); String str = (String) obj;、泛型擦除后集合强转元素 - 标准处理方式
- 前置判断:转换前用
instanceof校验对象实际运行时类型,再执行强转; - 简化方案:Java 14+ 模式匹配,一步完成「类型判断+强制转换」,简化代码;
- 根源规避:集合操作强制指定泛型(如
List<String> list = new ArrayList<>()),编译期拦截非目标类型元素。
- 前置判断:转换前用
- 核心代码示例
Object obj = new Integer(10);
// 1. 传统方式:instanceof判断+强转
if (obj instanceof String) {
String str = (String) obj;
}
// 2. Java14+ 模式匹配(推荐,少一层代码)
if (obj instanceof String str) {
System.out.println(str.length());
}
// 3. 泛型规避(从根源避免)
List<String> list = new ArrayList<>();
list.add("java");
// list.add(10); // 编译期直接报错,无法添加非String类型
5. InputMismatchException —— Scanner输入专属
- 核心含义:
java.util.Scanner读取数据时,输入数据类型与预期读取类型不兼容 - 典型场景:用
scanner.nextInt()读整数,用户输入字符串(“abc”)、小数(3.14) - 标准处理方式(核心:清空输入缓冲区,避免死循环)
- 推荐方案:先判断再读取,使用Scanner的
hasNextXxx()系列方法匹配读取方法(hasNextInt()对应nextInt()); - 兜底方案:捕获异常后,必须调用
scanner.next()清空缓冲区的无效数据; - 万能方案:先读取原始字符串,再通过包装类手动转换,配合
try-catch处理。
- 推荐方案:先判断再读取,使用Scanner的
- 核心代码示例(推荐方案,无异常)
Scanner scanner = new Scanner(System.in);
int num = 0;
while (true) {
System.out.print("请输入整数:");
if (scanner.hasNextInt()) {
num = scanner.nextInt();
break; // 输入合法,退出循环
} else {
System.err.println("输入错误,仅支持整数!");
scanner.next(); // 关键:清空缓冲区的无效数据,避免死循环
}
}
6. ArithmeticException —— 数值计算错误
- 核心含义:算术运算中出现非法操作,整数除零/取模模数为0是最典型场景
- 典型场景:
int a = 10 / 0;、10 % 0(注:浮点数除零结果为Infinity,不会触发此异常) - 标准处理方式
- 前置校验:对除法/取模的除数/模数做非零校验,从根源避免;
- 异常兜底:捕获异常后,根据业务返回默认值或抛出自定义提示,避免程序崩溃。
- 核心代码示例
int a = 10, b = 0;
int res = 0;
// 前置校验(推荐)
if (b != 0) {
res = a / b;
} else {
System.err.println("除数不能为零");
res = 0; // 业务默认值
}
// 异常兜底(无法提前校验的场景)
try {
res = a / b;
} catch (ArithmeticException e) {
System.err.println("计算失败:除数不能为零");
res = 0;
}
7. IllegalArgumentException —— 参数非法通用异常
- 核心含义:方法接收到不符合业务要求的非法参数,是自定义方法参数校验的标准异常
- 典型场景:方法要求参数>0却传入-1、要求非空字符串却传入空串、
Collections.sort(null) - 标准处理方式
- 主动抛出:方法入口处做参数校验,参数不合法时主动抛出该异常,并携带明确的错误提示;
- 工具辅助:使用
Objects/Apache Commons工具类简化参数校验,避免重复代码; - 框架适配:Spring项目可使用
@Valid/@NotBlank等注解做参数自动校验,无需手动判断。
- 核心代码示例
// 手动参数校验+主动抛出异常(推荐,语义清晰)
public void setAge(int age) {
if (age < 0 || age > 150) {
throw new IllegalArgumentException("年龄必须在0-150之间,当前值:" + age);
}
this.age = age;
}
// Spring项目注解校验(简化代码)
public void addUser(@Valid User user) {
// User类中:@NotBlank(message = "用户名不能为空") private String name;
}
8. NumberFormatException —— 数值格式转换错误
- 核心含义:将非数值格式的字符串转换为int/double/long等数值类型时触发
- 典型场景:
Integer.parseInt("123a");、Double.parseDouble("3.14.5");、前端传参非数值字符串后端直接转换 - 标准处理方式
- 异常捕获:转换时通过
try-catch捕获异常,返回业务默认值或提示格式错误; - 工具辅助:使用
org.apache.commons.lang3.math.NumberUtils,转换失败返回默认值,无需手动捕获; - 前置校验:转换前通过正则表达式校验字符串是否为合法数值(如
^\\d+$匹配整数)。
- 异常捕获:转换时通过
- 核心代码示例
String str = "123a";
// 1. try-catch兜底
int num1 = 0;
try {
num1 = Integer.parseInt(str);
} catch (NumberFormatException e) {
System.err.println("数值格式错误,默认值为0");
}
// 2. NumberUtils工具类(推荐,简化代码)
int num2 = NumberUtils.toInt(str, 0); // 转换失败返回默认值0
double num3 = NumberUtils.toDouble(str, 0.0);
9. ConcurrentModificationException —— 集合并发修改错误
- 核心含义:单/多线程中,遍历集合的同时执行结构性修改(增/删/修改集合容量)
- 典型场景:增强for循环遍历List时调用
list.remove()、多线程同时操作非线程安全集合(ArrayList/HashMap) - 标准处理方式(分单/多线程场景)
- 单线程:使用迭代器(Iterator) 遍历并修改,调用
it.remove(),这是集合遍历修改的标准方式; - 多线程:替换为线程安全集合(
CopyOnWriteArrayList替代ArrayList、ConcurrentHashMap替代HashMap); - 兜底方案:遍历前将集合转为数组,或遍历过程中收集需要修改的元素,遍历完成后统一处理。
- 单线程:使用迭代器(Iterator) 遍历并修改,调用
- 核心代码示例
List<String> list = new ArrayList<>();
list.add("a"); list.add("b"); list.add("c");
// 1. 单线程安全修改(迭代器)
Iterator<String> it = list.iterator();
while (it.hasNext()) {
if ("a".equals(it.next())) {
it.remove(); // 无异常,标准方式
}
}
// 2. 多线程安全集合(直接替换,无需修改业务代码)
List<String> safeList = new CopyOnWriteArrayList<>();
Map<String, String> safeMap = new ConcurrentHashMap<>();
10. UnsupportedOperationException —— 不支持的操作
- 核心含义:调用了对象未实现/不支持的方法,多为只读/固定长度对象的修改操作
- 典型场景:
Arrays.asList(arr).add(1);(该List为固定长度)、对Collections.unmodifiableList()执行增删 - 标准处理方式
- 根源规避:若需修改数组转换的List,重新创建可修改集合(
new ArrayList<>(Arrays.asList(arr))); - 开发规范:使用集合前确认其类型,避免对只读集合执行修改操作;
- 前置判断:通过集合的
class判断是否为可修改类型(兜底方案)。
- 根源规避:若需修改数组转换的List,重新创建可修改集合(
- 核心代码示例
String[] arr = {"a", "b"};
// 错误:固定长度List,无法修改
// List<String> list = Arrays.asList(arr);
// 正确:重新创建可修改ArrayList
List<String> list = new ArrayList<>(Arrays.asList(arr));
list.add("c"); // 正常执行
二、受检异常(Checked Exception)—— 外部环境异常,强制处理,资源释放
继承自java.lang.Exception(非RuntimeException子类),编译期必须通过try-catch捕获或throws声明抛出,多由程序外部环境异常导致(如文件不存在、网络断开),核心处理原则是强制捕获处理,核心操作是「释放资源+业务兜底」。
1. IOException(及子类)—— IO操作核心异常(最常用)
- 核心含义:所有IO操作的通用异常父类,子类覆盖具体场景:
FileNotFoundException(文件不存在)、SocketException(网络断开)、EOFException(文件提前结束) - 典型场景:文件读写、流的打开/关闭、网络数据传输、控制台输入流操作
- 标准处理方式(核心:保证IO资源100%释放)
- 优雅方案:Java 7+ try-with-resources 语法(自动关闭实现
AutoCloseable接口的资源,替代finally,推荐); - 传统方案:
try-catch-finally,在finally块中手动关闭资源(需判空,避免空指针); - 业务兜底:捕获异常后记录日志,返回友好的业务提示(如“文件读取失败”),避免暴露底层异常。
- 优雅方案:Java 7+ try-with-resources 语法(自动关闭实现
- 核心代码示例(try-with-resources 自动释放资源,推荐)
// 流对象实现AutoCloseable,try代码块结束后自动关闭,无需手动finally
try (FileReader fr = new FileReader("test.txt");
BufferedReader br = new BufferedReader(fr)) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (FileNotFoundException e) {
System.err.println("业务提示:文件不存在,请检查路径");
log.error("文件读取失败,路径:test.txt", e); // 记录详细日志(含堆栈)
} catch (IOException e) {
System.err.println("业务提示:文件读取失败");
log.error("文件读写异常", e);
}
- 关键子类:
FileNotFoundException(优先捕获,精准定位文件问题)、SocketException(网络IO,需增加重连逻辑)。
2. InterruptedException —— 线程中断协作异常
- 核心含义:线程处于可中断阻塞状态时,被其他线程调用
interrupt()中断,是线程间的「协作中断信号」(非错误异常) - 典型场景:线程执行
Thread.sleep()/Object.wait()/CountDownLatch.await()/Thread.join()时被中断 - 关键特性:异常触发后,JVM会自动清除线程的中断状态(
isInterrupted()返回false),切勿空catch吞掉异常(并发编程大忌) - 标准处理方式(核心三原则:恢复状态/释放资源/优雅终止,分3种场景)
- 工具方法场景:捕获异常后恢复中断状态(
Thread.currentThread().interrupt())+ 向上抛出异常,让上层调用方处理; - 线程入口场景:捕获异常后立即释放资源(关闭流/释放锁)+ 直接终止线程(
return); - 批量任务场景:恢复中断状态 + 跳过当前任务,让后续代码检测到中断并处理。
- 工具方法场景:捕获异常后恢复中断状态(
- 核心代码示例(工具方法+线程入口,最常用)
// 场景1:工具方法(不负责线程生命周期,向上抛出)
public void doBlockingWork() throws InterruptedException {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断状态,让上层感知
throw e; // 向上抛出
}
}
// 场景2:线程入口(最终处理,释放资源+终止)
Thread worker = new Thread(() -> {
FileWriter writer = null;
try {
writer = new FileWriter("log.txt");
doBlockingWork(); // 调用工具方法
} catch (InterruptedException e) {
System.out.println("收到中断请求,开始优雅终止");
// 步骤1:释放资源
if (writer != null) {
try { writer.close(); } catch (IOException ex) { log.error("资源释放失败", ex); }
}
// 步骤2:终止线程
return;
} catch (IOException e) {
log.error("IO异常", e);
}
});
worker.start();
worker.interrupt(); // 主线程触发中断
3. SQLException —— 数据库JDBC操作专属
- 核心含义:执行数据库操作(增删改查、连接、关闭)时触发,覆盖连接失败、SQL语法错误、表/字段不存在等场景
- 典型场景:数据库地址/账号密码错误、SQL语句拼写错误、操作不存在的表、连接池耗尽
- 标准处理方式(核心:资源释放+事务回滚+隐藏敏感信息)
- 资源管理:使用try-with-resources自动关闭
Connection/Statement/ResultSet(均实现AutoCloseable),避免数据库连接泄漏; - 事务处理:异常时执行事务回滚(
conn.rollback()),避免数据不一致; - 日志与提示:记录详细日志(含SQL语句、参数),返回通用业务提示(如“数据库操作失败”),避免暴露数据库地址/账号等敏感信息;
- 重试机制:对连接超时、网络抖动等临时异常,增加重试逻辑(配合Guava Retryer/Spring Retry)。
- 资源管理:使用try-with-resources自动关闭
- 核心代码示例
String sql = "INSERT INTO user (name) VALUES (?)";
// try-with-resources 自动关闭数据库资源
try (Connection conn = DBUtil.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql)) {
conn.setAutoCommit(false); // 关闭自动提交,开启事务
pstmt.setString(1, "test");
pstmt.executeUpdate();
conn.commit(); // 提交事务
} catch (SQLException e) {
// 事务回滚
if (conn != null) {
try { conn.rollback(); } catch (SQLException ex) { log.error("事务回滚失败", ex); }
}
log.error("SQL执行失败,SQL:{}", sql, e); // 记录详细日志
System.err.println("业务提示:数据保存失败,请稍后重试"); // 通用提示
}
4. ClassNotFoundException —— 类加载异常
- 核心含义:JVM在类加载过程中,无法找到指定全限定名的类文件(包名+类名)
- 典型场景:反射加载类时类名写错(
Class.forName("com.test.User"))、项目依赖缺失、classpath未包含该类 - 标准处理方式
- 基础排查:检查类的全限定名是否拼写正确(包名、类名大小写);
- 环境检查:确认项目运行时的classpath包含该类的class文件/依赖包;
- 异常处理:捕获异常后记录详细日志(类名、classpath信息),返回明确的排查提示。
- 核心代码示例
try {
Class<?> cls = Class.forName("com.test.User");
Object obj = cls.newInstance();
} catch (ClassNotFoundException e) {
log.error("类加载失败,类名:com.test.User,请检查类名/依赖", e);
System.err.println("系统异常:类加载失败,请联系开发人员");
} catch (InstantiationException | IllegalAccessException e) {
log.error("类实例化失败", e);
}
5. ParseException —— 日期/字符串解析异常
- 核心含义:对日期、自定义格式字符串进行解析/格式化时,输入格式与指定格式不匹配
- 典型场景:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); sdf.parse("2026/02/05") - 标准处理方式
- 根源规避:统一数据格式,前端传参做格式限制(如日期仅允许yyyy-MM-dd);
- 优雅方案:使用Java 8+ 新日期时间API(
LocalDate/DateTimeFormatter),线程安全且抛出更友好的DateTimeParseException(运行时异常); - 异常捕获:解析前校验输入格式,捕获异常后返回默认值或友好提示。
- 核心代码示例(推荐新日期API,替代传统SimpleDateFormat)
String dateStr = "2026/02/05";
// 传统方式(SimpleDateFormat,非线程安全)
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date date = sdf.parse(dateStr);
} catch (ParseException e) {
System.err.println("日期格式错误,请按yyyy-MM-dd输入");
}
// Java8+ 新日期API(推荐,线程安全,异常更友好)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
try {
LocalDate date = LocalDate.parse(dateStr, formatter);
} catch (DateTimeParseException e) { // 运行时异常,无需强制捕获
System.err.println("日期格式错误,请按yyyy-MM-dd输入");
}
三、JVM错误(Error)—— 系统层面严重问题,提前规避,无需处理
继承自java.lang.Error,属于JVM/系统层面的严重异常,程序无法捕获和恢复,一旦发生通常导致程序崩溃,核心处理原则是提前规避,通过代码优化/JVM调优/环境配置防止发生,无需在代码中手动捕获。
1. OutOfMemoryError(OOM)—— 内存溢出
- 核心含义:JVM堆内存、方法区、元空间等内存区域耗尽,无法为新对象分配内存
- 典型场景:无限循环创建大对象、集合存储大量数据未清理(内存泄漏)、JVM堆内存设置过小(
-Xmx配置不合理)、静态集合持有大量对象引用 - 标准规避方式
- 代码优化:及时释放无用对象引用(如集合使用后清空、避免静态集合存储业务数据),排查内存泄漏(使用MAT/JProfiler工具);
- JVM调优:合理设置堆内存参数(
-Xms初始堆 =-Xmx最大堆,避免内存频繁扩容,如-Xms2G -Xmx2G),调整元空间大小(-XX:MetaspaceSize=256M); - 业务优化:采用分页查询/流式处理替代全量加载数据,避免一次性将大量数据加载到内存。
2. StackOverflowError —— 栈溢出
- 核心含义:JVM方法调用栈的深度超过最大值,无限递归是最典型、最常见的场景
- 典型场景:无限递归调用方法(
public void test() { test(); })、方法调用链过长(多层级业务方法嵌套) - 标准规避方式
- 代码优化:杜绝无限递归,检查递归方法的终止条件,确保能正常退出;若递归层级过深,改为循环实现(根本解决方案);
- 调优辅助:调整JVM栈大小参数(
-Xss,如-Xss1M),增大方法调用栈深度(谨慎使用,治标不治本); - 代码重构:将过长的方法调用链拆分为多个独立方法,减少嵌套层级。
- 避坑点:切勿依赖调整
-Xss解决问题,无限递归即使增大栈大小,最终仍会触发栈溢出。
3. NoClassDefFoundError —— 类定义未找到
- 核心含义:编译期能找到类,但运行期JVM无法找到该类的字节码文件(与
ClassNotFoundException的核心区别:前者是运行期类加载失败,后者是编译/反射时类不存在) - 典型场景:编译后删除了类的class文件、依赖的第三方包编译期存在但运行期缺失、Maven/Gradle依赖包版本冲突
- 标准规避方式
- 环境检查:确认项目运行时的classpath包含所有依赖包,编译后的class文件完整无缺失;
- 依赖管理:使用Maven/Gradle统一管理依赖,执行
clean install清理并重新编译项目,避免依赖包缺失/冲突; - 类加载器排查:避免自定义类加载器的加载范围冲突,确保类被JVM正确加载。
四、Java 常见异常速查表(含核心处理方式,快速查阅)
| 分类 | 异常名称 | 核心关键词 | 核心处理/规避方式 |
|---|---|---|---|
| 运行时异常 | NullPointerException | 空对象、自动拆箱 | Optional包装/Objects非空校验/返回空对象而非null |
| ArrayIndexOutOfBoundsException | 数组索引越界 | 增强for循环/索引前置校验/以length为边界 | |
| IndexOutOfBoundsException | 集合/字符串索引越界 | 非空校验/以size/length为边界/Apache工具类辅助 | |
| ClassCastException | 强制类型转换错误 | instanceof判断/Java14+模式匹配/集合指定泛型 | |
| InputMismatchException | Scanner输入类型不匹配 | hasNextXxx()前置判断/清空输入缓冲区/先读字符串再转换 | |
| ArithmeticException | 整数除零、非法算术运算 | 除数非零校验/try-catch兜底返回默认值 | |
| IllegalArgumentException | 方法参数非法 | 方法入口校验/主动抛出异常/Spring注解校验 | |
| NumberFormatException | 字符串转数值格式错误 | NumberUtils工具类/正则校验/try-catch兜底 | |
| ConcurrentModificationException | 集合并发修改 | 迭代器修改/线程安全集合/遍历后统一修改 | |
| UnsupportedOperationException | 不支持的操作 | 重新创建可修改集合/避免修改只读集合 | |
| 受检异常 | IOException(及子类) | 文件/流/网络IO操作 | try-with-resources自动关资源/finally释放/日志+业务提示 |
| InterruptedException | 线程阻塞时被中断 | 恢复中断状态/释放资源/优雅终止/切勿吞异常 | |
| SQLException | 数据库JDBC操作 | 自动关连接/事务回滚/详细日志/通用业务提示 | |
| ClassNotFoundException | 反射/类加载找不到类 | 检查类名拼写/确认依赖完整/排查classpath | |
| ParseException | 日期/字符串解析格式不匹配 | 统一格式/Java8+新日期API/前置格式校验 | |
| JVM错误 | OutOfMemoryError | 内存溢出、OOM | 排查内存泄漏/JVM堆调优/分页/流式处理/释放无用引用 |
| StackOverflowError | 栈溢出、无限递归 | 杜绝无限递归/递归改循环/调整-Xss/拆分长调用链 | |
| NoClassDefFoundError | 运行期找不到类定义 | 检查classpath/重新编译项目/Maven/Gradle统一依赖管理 |
五、Java 异常处理通用最佳实践(所有场景均适用)
- 切勿空catch吞掉异常:尤其是
InterruptedException、IO异常、SQL异常,空catch会导致问题无法定位、资源泄漏、程序逻辑混乱; - 异常处理粒度适中:不要用一个try-catch捕获所有异常(如
catch (Exception e)),按异常类型细分处理,便于精准定位问题; - 资源释放是核心:涉及IO、数据库、网络连接等资源的操作,必须保证资源释放(优先使用try-with-resources);
- 日志记录要完整:捕获异常时记录异常堆栈+业务上下文(如参数、SQL语句),避免仅打印
e.printStackTrace(); - 前端/用户提示要友好:隐藏底层异常细节(如数据库地址、SQL语句),返回通用的业务提示(如“操作失败,请稍后重试”);
- 运行时异常以预防为主:通过判空、参数校验、索引检查等逻辑从根源避免,而非依赖try-catch;
- 自定义异常语义清晰:复杂业务中自定义异常(继承Exception/RuntimeException),让异常更贴合业务场景(如
UserNotExistException),便于统一处理。 - 运行时异常:重点在「预防」,通过严谨的代码逻辑(判空、参数校验、索引检查、泛型使用)避免,是日常bug排查的主要对象;
- 受检异常:重点在「处理」,编译期强制捕获/抛出,需根据业务场景做兜底(如IO异常关闭流、SQL异常回滚事务);
- Error:重点在「规避」,通过合理的JVM参数配置(如调整堆内存)、优化代码(避免无限递归)防止,程序无法处理;
- 异常处理原则:切勿空catch吞掉异常(尤其是
InterruptedException),异常处理的核心是「恢复状态、释放资源、优雅提示/终止」。
掌握以上异常的处理方式和通用原则,能大幅提升Java代码的健壮性和可维护性,快速定位并解决开发中的各类异常问题,同时避免因异常处理不当导致的资源泄漏、程序崩溃、数据不一致等严重问题。
总结
到此这篇关于Java常见异常全面梳理的文章就介绍到这了,更多相关Java常见异常内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
SpringBoot中配置文件敏感信息加密解密的实现方案详解
在现代企业级应用中,application.yml 或 application.properties 常用于配置数据库等中间件的连接信息,但将明文密码直接写入配置文件中存在诸多风险,下面我们就来看看如何对配置文件敏感信息加密解密吧2025-06-06
解读RedisTemplate的各种操作(set、hash、list、string)
这篇文章主要介绍了解读RedisTemplate的各种操作(set、hash、list、string),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教2023-12-12
Springboot+Redis实现API接口限流的示例代码
本文主要介绍了Springboot+Redis实现API接口限流的示例代码,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下2021-07-07
在Mac系统上安装Java和IntelliJ IDEA完整笔记
IntelliJ IDEA的智能代码辅助功能堪称一绝,它具备强大的代码自动补全能力,能依据上下文精准推测开发者的意图,提供极为准确的代码建议,这篇文章主要介绍了在Mac系统上安装Java和IntelliJ IDEA的相关资料,需要的朋友可以参考下2026-02-02


最新评论