当前位置: 首页 > 知识库问答 >
问题:

在try-with-resources块中管理多个链接资源是否正确?

文心思
2023-03-14

当只使用一个autocloseable资源时,Java7 try-with-resources语法(也称为ARM块(自动资源管理))是很好的、简短的和直接的。但是,当我需要声明多个相互依赖的资源时,我不确定什么是正确的习惯用法,例如FileWriter和包装它的BufferedWriter。当然,这个问题涉及包装某些autocloseable资源的任何情况,而不仅仅是这两个特定的类。

我想出了以下三种选择:

static void printToFile1(String text, File file) {
    try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
        bw.write(text);
    } catch (IOException ex) {
        // handle ex
    }
}

这个很好,很短,但是坏了。因为底层的文件编写器不是在变量中声明的,所以它永远不会在生成的finally块中直接关闭。它将仅通过包装BufferedWriterClose方法关闭。问题是,如果从bw的构造函数引发异常,则不会调用其close,因此不会关闭基础的文件编写器

static void printToFile2(String text, File file) {
    try (FileWriter fw = new FileWriter(file);
            BufferedWriter bw = new BufferedWriter(fw)) {
        bw.write(text);
    } catch (IOException ex) {
        // handle ex
    }
}

在这里,底层资源和包装资源都在ARM管理的变量中声明,因此它们肯定都将被关闭,但底层fw.close()将被调用两次:不仅是直接调用,而且是通过包装的bw.close()调用。

对于这两个实现closeable(它是autocloseable的子类型)的特定类来说,这不应该是一个问题,它们的契约声明允许对close进行多次调用:

关闭此流并释放与之关联的所有系统资源。如果流已经关闭,则调用此方法不起作用。

但是,在一般情况下,我可以拥有只实现autocloseable(而不是closeable)的资源,这不能保证可以多次调用close:

注意,与java.io.Closeable的close方法不同,这个close方法不要求是幂等的。换句话说,多次调用此close方法可能会产生一些明显的副作用,这与CloSeable.close不同,如果多次调用此close方法则要求close不起作用。但是,强烈鼓励该接口的实现者使其闭式方法是幂等的。

static void printToFile3(String text, File file) {
    try (FileWriter fw = new FileWriter(file)) {
        BufferedWriter bw = new BufferedWriter(fw);
        bw.write(text);
    } catch (IOException ex) {
        // handle ex
    }
}

另一方面,语法有点不规范,而且Eclipse会发出一个警告,我认为这是一个错误警报,但仍然是一个必须处理的警告:

资源泄漏:“BW”从未关闭

那么,该走哪条路呢?还是我错过了其他正确的成语?

共有1个答案

凌博实
2023-03-14

以下是我对其他选择的看法:

try (BufferedWriter bw = new BufferedWriter(new FileWriter(file))) {
    bw.write(text);
}

对我来说,15年前从传统的C++来到Java最棒的事情就是你可以信任你的程序。即使事情变得一团糟和出错(他们经常这样做),我也希望代码的其余部分保持最佳行为和良好的气味。实际上,BufferedWriter可能会在这里引发异常。例如,内存耗尽并不稀奇。对于其他decorator,您知道哪些java.io包装类从其构造函数中抛出检查异常吗?我不想。如果你依赖于那种晦涩难懂的知识,对代码的可理解性没有多大帮助。

还有“毁灭”。如果存在错误条件,那么您可能不希望将垃圾冲到需要删除的文件中(未显示该错误的代码)。当然,删除文件也是作为错误处理进行的另一个有趣的操作。

通常,您希望finally块尽可能短和可靠。html" target="_blank">添加同花顺无助于实现这一目标。对于许多版本,JDK中的一些缓冲类有一个bug,其中close中的flush异常导致修饰对象上的close无法调用。虽然这个问题已经解决了一段时间,但希望其他实现也能解决这个问题。

try (
    FileWriter fw = new FileWriter(file);
    BufferedWriter bw = new BufferedWriter(fw)
) {
    bw.write(text);
}

我们仍然在隐式finally块中进行刷新(现在使用重复的close-当添加更多的修饰符时,这会变得更糟),但是构造是安全的,我们必须隐式finally块,因此即使失败的flush也不会阻止资源释放。

try (FileWriter fw = new FileWriter(file)) {
    BufferedWriter bw = new BufferedWriter(fw);
    bw.write(text);
}

这里有个窃听器。应该是:

try (FileWriter fw = new FileWriter(file)) {
    BufferedWriter bw = new BufferedWriter(fw);
    bw.write(text);
    bw.flush();
}

一些实施不佳的装饰器实际上是资源,需要可靠地关闭。此外,有些流可能需要以特定的方式关闭(可能它们正在进行压缩,需要写入位来完成,而不能只是刷新所有内容)。

虽然3在技术上是一个优越的解决方案,但软件开发的原因使2成为更好的选择。但是,try-with-resource仍然是一个不适当的解决方法,您应该坚持使用Execute Around习语,它在Java SE8中应该有更清晰的闭包语法。

 类似资料:
  • 问题内容: 如何使用Java 7的自动资源管理(try-with- resources语句)集成创建/接收连接,查询数据库以及可能处理结果的通用JDBC习惯?(教程) 在Java 7之前,通常的模式是这样的: 使用Java 7,您可以: 这将关闭和,但是回滚又如何呢?我无法添加包含回滚的catch子句,因为该连接仅在try块内可用。 您是否还在try块之外定义连接?这里的最佳实践是什么,特别是如果

  • 一本关于Java的初学者书中有以下代码。这本书也很好地解释了异常,并且由于我理解了异常是如何工作的,我得到了一个关于下面代码的问题。 由于某种原因,如果FileWriter类抛出异常,将不会被执行。因此,我认为关闭writer对象的最佳位置是在finally块中。甚至在此之前,我已经看到过许多这样编写的代码,其中资源将在try块本身中关闭。我认为这样做是没有意义的。只有在没有例外的情况下,资源才会

  • 本文向大家介绍如何在Java 9中的try-with-resources语句中声明多个资源?,包括了如何在Java 9中的try-with-resources语句中声明多个资源?的使用技巧和注意事项,需要的朋友参考一下 在Java 9中对try-with-resources语句进行了改进。如果我们已经有一个最终的或等同于最终变量的资源,那么我们可以在try-with-resources语句中使用该

  • 问题内容: 使用try-with-resources语句关闭资源时,是否可以忽略抛出的异常? 例: 还是应该继续关闭? 问题答案: 我在钱币开发邮件列表中找到了这个答案:http : //mail.openjdk.java.net/pipermail/coin- dev/2009-April/001503.html 5. close方法的某些失败可以安全地忽略(例如,关闭已打开以供读取的文件)。

  • try-with-resources语句是一个try语句,其中包含一个或多个正式声明的资源。 这里资源是一个对象,一旦不再需要就应该关闭它。 try-with-resources语句确保在需求完成后关闭每个资源。 任何实现java.lang.AutoCloseable或java.io.Closeable的对象,接口都可以用作资源。 在Java 9之前,资源将在try之前或try语句内部声明,如下面

  • 主要内容:Java SE 7:Try-With-Resources基础知识,Java SE 7:Try-With-Resources规则,Java SE 9:Try-With-Resources改进在这篇文章中,我们将讨论Java SE 9中的一些改进语句。现在让我们开始学习这个构造。 Java SE 7:Try-With-Resources基础知识 Java SE 7引入了一个新的构造: 语句,用于更好的异常处理。 如果没有这个构造,开发人员必须编写大量冗余和难看的代码。 如果开发人员忘记正确