今日总结10.22

时间:2024-10-22 20:38:57

如何使用 try-with-resources代替try-catch-finally

1.适用范围(资源的定义): 任何实现 java.lang.AutoCloseable或者 java.io.Closeable 的对象

2.关闭资源和 finally 块的执行顺序:try-with-resources 语句中,任何 catch 或 finally 块在声明的资源关闭后运行

《Effective Java》中明确指出:

面对必须要关闭的资源,我们总是应该优先使用 try-with-resources 而不是try-finally。随之产生的代码更简短,更清晰,产生的异常对我们也更有用。try-with-resources语句让我们更容易编写必须要关闭的资源的代码,若采用try-finally则几乎做不到这点。

Java 中类似于InputStreamOutputStreamScannerPrintWriter等的资源都需要我们调用close()方法来手动关闭,一般情况下我们都是通过try-catch-finally语句来实现这个需求,如下:

//读取文本文件的内容
Scanner scanner = null;
try {
    scanner = new Scanner(new File("D://read.txt"));
    while (scanner.hasNext()) {
        System.out.println(scanner.nextLine());
    }
} catch (FileNotFoundException e) {
    e.printStackTrace();
} finally {
    if (scanner != null) {
        scanner.close();
    }
}

使用 Java 7 之后的 try-with-resources 语句改造上面的代码:

try (Scanner scanner = new Scanner(new File("test.txt"))) {
    while (scanner.hasNext()) {
        System.out.println(scanner.nextLine());
    }
} catch (FileNotFoundException fnfe) {
    fnfe.printStackTrace();
}

当然多个资源需要关闭的时候,使用 try-with-resources 实现起来也非常简单,如果你还是用try-catch-finally可能会带来很多问题。

通过使用分号分隔,可以在try-with-resources块中声明多个资源。

try (BufferedInputStream bin = new BufferedInputStream(new FileInputStream(new File("test.txt")));
     BufferedOutputStream bout = new BufferedOutputStream(new FileOutputStream(new File("out.txt")))) {
    int b;
    while ((b = bin.read()) != -1) {
        bout.write(b);
    }
}
catch (IOException e) {
    e.printStackTrace();
}

异常使用有哪些需要注意的地方

在异常使用中,有多个方面需要注意,以确保程序的健壮性、可读性和可维护性。以下是一些关键的注意事项:

一、异常处理的基本规范

  1. 提供精确、易读的错误原因信息
    • 在异常处理模块中,应确保提供的错误信息足够精确且易于理解,以便开发人员能够迅速定位并解决问题。
  2. 避免处理能够避免的异常
    • 对于可以通过改进代码逻辑或增加前置检查来避免的异常,应尽量避免在运行时处理。
  3. 限制异常抛出的类型
    • 一个方法不应抛出过多类型的异常,最好不超过三个,以减少调用者的处理负担。
  4. 避免在try及finally中使用return语句
    • 在try或finally块中使用return语句可能会导致异常信息丢失或程序流程混乱。
  5. 在finally中释放资源
    • 对于数据库连接、文件句柄等资源,应在finally块中释放,以防止资源泄露。
  6. 将try/catch置于循环之外
    • 尽量避免在循环内部使用try/catch块,因为这可能导致性能下降和代码可读性降低。
  7. 避免使用异常进行程序流程控制
    • 异常处理机制的效率低于条件分支,且跳转流程难以预测,因此应避免将异常用于程序流程控制。

二、异常捕获与处理的优化

  1. 细分异常处理
    • 应尽量捕获具体的异常类型,而不是直接捕获Exception或其父类。这有助于提供更准确的错误信息,并减少不必要的异常处理代码。
  2. 避免捕获unchecked Exception
    • 对于RuntimeException等unchecked异常,通常不应捕获,因为它们通常表示编程错误。应通过改进代码逻辑来避免这些异常的发生。
  3. 合理处理checked Exception
    • 对于checked异常,应根据实际情况进行处理。如果异常可以被修复,则进行修复;如果无法处理,则重新抛出异常,让调用者处理。
  4. 使用try-with-resources简化资源管理
    • 对于实现了AutoCloseable接口的资源,可以使用try-with-resources语句来自动管理资源,从而简化代码并提高安全性。

三、日志记录与异常信息

  1. 记录完整的异常信息
    • 在日志中记录完整的异常信息,包括异常类型、错误消息和堆栈跟踪。这有助于开发人员快速定位问题原因。
  2. 避免在日志中使用异常消息替代完整信息
    • 异常消息可能不包含有用的信息,因此应尽量避免仅记录异常消息而忽略其他重要的上下文信息。
  3. 使用合适的日志级别
    • 根据异常的严重程度选择合适的日志级别(如error、warn等),以便更好地监控和排查问题。
  4. 避免重复记录日志
    • 对于同一个异常,应避免在多个地方重复记录日志,以减少日志的冗余和噪声。

四、其他注意事项

  1. 不要混合使用异常机制和返回值
    • 应避免同时使用异常机制和返回值来进行异常处理,因为这会使程序的异常处理部分变得复杂且难以理解。
  2. 保持异常处理的简洁性
    • 异常处理代码应尽可能简洁明了,避免引入不必要的复杂性。
  3. 遵循最佳实践
    • 学习和遵循业界关于异常处理的最佳实践,以提高代码的质量和可维护性。