简体   繁体   English

Java try-with-resources 的缺点

[英]Disadvantages of Java try-with-resources

I have a method which loads a file into a reader.我有一种方法可以将文件加载到阅读器中。 Tests or other code can use this reader to read the file.测试或其他代码可以使用此阅读器读取文件。 The problem is that I cannot declare the reader outside of the try-with-resources/TWR block.问题是我不能在 try-with-resources/TWR 块之外声明读取器。 Is this a disadvantage of TWR or am I missing something ?这是 TWR 的缺点还是我遗漏了什么?

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class TestngTesting {
    BufferedReader fileReader;//Can't declare this as final, because its not assigned here itself.
    BufferedReader fileReader1;

    //Can be made @BeforeClass method.
    public void loadFile() throws IOException {
        fileReader = new BufferedReader(new FileReader("path/file.txt"));

        //Compile error - Variable used as a try-with-resources resource should be final or effectively final.
        try(fileReader){

        }

        try{
            fileReader1 = new BufferedReader(new FileReader("path/file.txt"));
        }finally {
            //end gracefully.
        }
    }
}

PS - I read these two posts before posting my question - link , link . PS - 我在发布我的问题之前阅读了这两篇文章 - 链接链接

It's not.它不是。

If you want to safely work with resources, you need to define some lexical scope within which the resource is valid, and anytime code transitions outside of this scope, it is invalid.如果你想安全地使用资源,你需要定义一些资源在其中有效的词法范围,并且任何时候代码转换到这个范围之外,它都是无效的。

Failure to do so means that neither the compiler nor any linting tool can track if you're doing it right, so now it's a tossup, and bugs are hard to detect.不这样做意味着编译器或任何 linting 工具都无法跟踪您是否做得对,所以现在它是一个折腾,并且很难检测到错误。 If you really want that, cool – but ARM is already right out, the point of ARM is to make it simple to do the lexical limitation thing.如果你真的想要那个,很酷——但 ARM 已经出来了,ARM 的重点是让词法限制的事情变得简单。

If you can't find a way to use a try-with-resources block (ARM) to do it, then you don't have the lexical scope situation.如果您找不到使用 try-with-resources 块 (ARM) 的方法,那么您就没有词法范围的情况。 However, that doesn't mean you're immediately doomed to the old unsafe-ish way.但是,这并不意味着您立即注定要采用旧的不安全的方式。

You can have a field containing a resource without losing ARM .可以拥有一个包含资源的字段而不会丢失 ARM

But, it does mean the object with that field must itself become AutoClosable - you can shift the burden of try-with-resources scoping elsewhere, to code that calls your resource-using code.但是,这确实意味着具有该字段的对象本身必须成为AutoClosable - 您可以将 try-with-resources 范围界定的负担转移到调用您的资源使用代码的代码。 Then all you have to do, is close that resource in your own close() method, which is the only method you have to implement if you implements AutoClosable (doing that lets other code try-with-resources instances of your class).然后您要做的就是在您自己的 close() 方法中关闭该资源,如果您implements AutoClosable ,这是您必须实现的唯一方法(这样做可以让其他代码尝试使用您的类的资源实例)。

Of course, if all you wanted was shift the declaration without a particularly sensible reason, ARM does indeed 'encode' the code style where you declare a variable only when you need it, and not the style where you declare everything at the top.当然,如果您想要的只是在没有特别合理的理由的情况下移动声明,ARM 确实会“编码”代码样式,您只在需要时声明变量,而不是在顶部声明所有内容的样式。

From my experience and perusing various style guides, 'declare all local vars at the top' is uncommon, and has downsides;根据我的经验并仔细阅读各种风格指南,“在顶部声明所有本地变量”并不常见,并且有缺点; declarations are lexically scoped.声明是词法范围的。 That's a good thing, and for something like ARM, crucial.这是一件好事,对于像 ARM 这样的东西,至关重要。 After all, I don't WANT to touch that variable once it's already closed, for the vast majority of resources, doing anything with them post-close() is an immediate exception anyway.毕竟,我不想碰这个变量,一旦它已经关闭,绝大多数的资源,这样做与他们任何关闭后()是一个即时异常反正。

The problem is that I cannot declare the reader outside of the try-with-resources/TWR block.问题是我不能在 try-with-resources/TWR 块之外声明读取器。 Is this a disadvantage of TWR or am I missing something ?这是 TWR 的缺点还是我遗漏了什么?

You can always declare and initialize it in the try-with-resources block:您始终可以在try-with-resources块中声明和初始化它:

try(BufferedReader fileReader = new BufferedReader(new FileReader("path/file.txt"))){
      // Print each line
      String line;
      while ((line = fileReader.readLine()) != null) {
          System.out.println(line);
      }
} catch (IOException e) {
     System.err.format("IOException: %s%n", e);
}

You can re-assign it to a local variable:您可以将其重新分配给局部变量:

public class TestngTesting {
    BufferedReader fileReader;

    public void loadFile() throws IOException {
        fileReader = new BufferedReader(new FileReader("path/file.txt"));

        try (BufferedReader r = fileReader) {

        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM