尝试使用资源文件编写器是一种好的做法吗?

2022-09-02 10:24:49

我在网络和Joshua Bloch的“Effective Java”一书中看到了这个例子。

try(BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))){
  writer.write(str); // do something with the file we've opened
}
catch(IOException e){
  // handle the exception
}

此示例没有问题,它将自动关闭,反过来,将关闭 ;但是,在其他情况下,如果我们以这种方式声明 2 个嵌套资源:BufferedWriterFileWriter

try (AutoClosable res = new Impl2(new Impl1())) {... }

我想它可能会发生,表现良好,但崩溃,在这种情况下,Java不会引用,以便关闭它。new Impl1()new Impl2()Impl1

总是独立声明多个资源(即使在这种情况下不需要),这难道不是一种更好的做法吗?

try(FileWriter fw = new FileWriter(fileName); 
    BufferedWriter writer = new BufferedWriter(fw)){ ... }

答案 1

经过一番搜索,我能够找到这篇文章:https://dzone.com/articles/carefully-specify-multiple-resources-in-single-try

根据定义 JLS 14.20.3 a 由 s 组成,由 .基于此,我们可以得出结论,嵌套初始化是单个资源。由于为多个资源定义的规则在这里不适用,因此重要的规则是:ResourceListResource;AutoClosable res = new Impl2(new Impl1())try-with-resources

资源按从左到右的顺序进行初始化。如果资源无法初始化(即,其初始值设定项表达式引发异常),则到目前为止由 try-with-resources 语句初始化的所有资源都将关闭。如果所有资源都成功初始化,则 try 块将正常执行,然后关闭 try-with-resources 语句的所有非空资源。

资源的关闭顺序与初始化顺序相反。仅当资源初始化为非空值时,才会关闭资源。关闭一个资源时出现异常不会阻止其他资源的关闭。如果异常之前由初始值设定项、try 块或资源关闭引发,则会禁止出现此类异常。

更重要的是,除非它被显式调用,否则不会被调用Implt1#close()Impl2#close()

简而言之,最好在单独的语句中声明多个资源,并用 分隔,如下所示:;

try(Impl1 impl1 = new Impl1(); 
    Impl2 impl2 = new Impl2(impl1))

答案 2

如果异常发生在 try 部分,则没有资源泄漏(假设 Impl1 写得好)。请注意,在 中引发的异常不会到达,因为在调用构造函数参数之前会对其进行计算。Impl1()Impl2

try (AutoClosable res = new Impl2(new Impl1())) {

因此,嵌套这样的包装构造函数是可以的;如果代码不会变得很长,则样式更好。

一个评论:并且是使用平台编码的旧实用程序类,每个应用程序安装会有所不同。FileWriterFileReader

Path path = Paths.get(fileName);
try (BufferedWriter writer =
        Files.newBufferedWriter​(path, StandardCharsets.UTF8)) {

推荐