Java 开发中的 9 个异常处理的避坑技巧:实战案例解析

文章目录

        • 1. 不要滥用 catch 一切的异常
        • 2. 使用自定义异常明确表达业务逻辑
        • 3. 切勿在 finally 中使用 return
        • 4. 避免吞掉异常
        • 5. 避免在循环中创建异常
        • 6. 利用 `try-with-resources` 自动关闭资源
        • 7. 避免使用异常控制流程
        • 8. 避免频繁创建和抛出自定义异常
        • 9. 细分捕获异常类型
        • 总结
        • 推荐阅读文章

在 Java 开发中,异常处理是不可避免的一个重要环节。然而,不当的异常处理会影响系统的稳定性和性能。本篇文章总结了 9 个异常处理的避坑技巧,并通过实战案例展示如何更好地处理异常。


1. 不要滥用 catch 一切的异常

滥用 catch (Exception e)catch (Throwable t) 捕获所有异常,虽然可以防止程序崩溃,但会导致难以定位问题的根本原因。建议只捕获特定的异常类型。

案例

try {
    int result = 10 / 0;
} catch (Exception e) {
    System.out.println("发生了异常!");
}

正确做法

try {
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("除数为零错误!");
}

解析:捕获特定异常可以让程序更具可读性,并且可以更快定位异常源头。


2. 使用自定义异常明确表达业务逻辑

使用标准异常(如 IllegalArgumentException)有时无法准确表达业务问题。自定义异常可以帮助明确异常来源,便于调试和日志分析。

案例

public class InsufficientFundsException extends Exception {
    public InsufficientFundsException(String message) {
        super(message);
    }
}

public void withdraw(double amount) throws InsufficientFundsException {
    if (amount > balance) {
        throw new InsufficientFundsException("余额不足");
    }
}

解析:自定义异常有助于清晰描述异常情况,提高代码可维护性。


3. 切勿在 finally 中使用 return

finally 中使用 return 会掩盖 trycatch 中的返回值,可能导致结果与预期不符。

案例

public int getValue() {
    try {
        return 10;
    } finally {
        return 20; // 错误:覆盖了 try 的返回值
    }
}

解析:在 finally 中返回值会覆盖 try 中的值,应避免此类写法。


4. 避免吞掉异常

如果 catch 块中不处理异常也不记录日志,就会“吞掉”异常,导致错误无法追踪。应确保所有异常都有记录,方便后续排查。

案例

try {
    // some code
} catch (IOException e) {
    // 错误:吞掉异常,后续难以定位问题
}

正确做法

try {
    // some code
} catch (IOException e) {
    e.printStackTrace(); // 或记录到日志中
}

解析:即使暂时不处理异常,也应当记录,以备后续排查。


5. 避免在循环中创建异常

在循环中创建异常(例如,每次都抛出 Exception)会导致性能问题。异常创建成本较高,应避免重复创建。

案例

for (int i = 0; i < 1000; i++) {
    try {
        throw new Exception("循环中的异常"); // 错误:反复创建异常对象
    } catch (Exception e) {
        e.printStackTrace();
    }
}

解析:循环中的异常应尽量避免,可改为条件判断或提前退出循环。


6. 利用 try-with-resources 自动关闭资源

手动关闭资源容易忽略某些情况,造成资源泄漏。try-with-resources 自动关闭资源,简化代码并降低泄漏风险。

案例

try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
    // 读取文件
} catch (IOException e) {
    e.printStackTrace();
}

解析try-with-resources 是 Java 7 引入的一种语法糖,简化资源管理,推荐使用。


7. 避免使用异常控制流程

异常控制流程是指利用异常作为逻辑判断的手段,这种做法会导致性能下降且代码难以维护。

案例

try {
    int result = 10 / 0; // 利用异常控制流程
} catch (ArithmeticException e) {
    // 错误:用异常处理业务逻辑
}

正确做法

if (denominator != 0) {
    int result = 10 / denominator; // 使用条件判断而非异常
} else {
    System.out.println("除数不能为零!");
}

解析:异常应只用于处理意外情况,避免其用于业务逻辑。


8. 避免频繁创建和抛出自定义异常

频繁创建和抛出自定义异常会增加系统开销。对于经常发生的异常,应考虑是否可以使用条件判断代替。

案例

public void validate(int age) throws InvalidAgeException {
    if (age < 0 || age > 150) {
        throw new InvalidAgeException("年龄不合法"); // 错误:频繁抛出异常
    }
}

正确做法

public void validate(int age) {
    if (age < 0 || age > 150) {
        System.out.println("年龄不合法"); // 使用条件判断减少异常抛出
    }
}

解析:频繁抛出异常会影响性能,应尽量减少不必要的异常抛出。


9. 细分捕获异常类型

多个异常类型共用一个 catch 块会导致日志信息不明确。应尽可能地细分异常类型,便于定位错误。

案例

try {
    // some code
} catch (Exception e) { // 捕获所有异常,难以追踪具体问题
    e.printStackTrace();
}

正确做法

try {
    // some code
} catch (IOException e) {
    System.out.println("IO 异常:" + e.getMessage());
} catch (SQLException e) {
    System.out.println("SQL 异常:" + e.getMessage());
}

解析:通过细分异常类型,可以更准确地追踪和处理不同的异常。


总结

掌握以上 9 个异常处理的避坑技巧,可以帮助 Java 开发者更好地处理和定位异常,提高代码的健壮性和可维护性。

推荐阅读文章
  • 由 Spring 静态注入引发的一个线上T0级别事故(真的以后得避坑)
  • 如何理解 HTTP 是无状态的,以及它与 Cookie 和 Session 之间的联系
  • HTTP、HTTPS、Cookie 和 Session 之间的关系
  • 使用 Spring 框架构建 MVC 应用程序:初学者教程
  • 有缺陷的 Java 代码:Java 开发人员最常犯的 10 大错误
  • Java Spring 中常用的 @PostConstruct 注解使用总结
  • 线程 vs 虚拟线程:深入理解及区别
  • 深度解读 JDK 8、JDK 11、JDK 17 和 JDK 21 的区别
  • 10大程序员提升代码优雅度的必杀技,瞬间让你成为团队宠儿!
  • 探索 Lombok 的 @Builder 和 @SuperBuilder:避坑指南(一)
  • 为什么用了 @Builder 反而报错?深入理解 Lombok 的“暗坑”与解决方案(二)
上一篇:Trimble X12三维激光扫描仪正在改变游戏规则【上海沪敖3D】


下一篇:【excel基本操作-sumif绝对引用和相对引用