为什么可以在其 try-with-resources 范围之外使用 Closed 对象?

Why is it possible to use a Closed object outside of its try-with-resources scope?

I've read 在 try-with-resources 块中初始化的资源仅在该块的持续时间内在范围内。

如果是这样的话,那么这段代码似乎是如何解决这个问题的?

public class Main {
    public static void main(String[] args) throws Exception {
        final Main main = new Main();

        try {
            final char[] buffer = new char[10];
            StringReader stringReader = main.testStream();
            System.out.println(stringReader.read(buffer, 0, 10));
        } catch (IOException e) {
            System.out.println("expected IOException caught here"); 
        }

        try {
            HttpResponse response = main.tryResponse();
            response.getEntity();
            System.out.println("should not reach this line if response is out of scope");
        } catch (Exception e) {
            System.out.println("why no IOException here?");
        }
    }

    StringReader tryStream() throws IOException {
        try (StringReader reader = new StringReader("string")) {
            return reader;
        }
    }

    HttpResponse tryResponse() throws IOException {
        CloseableHttpClient client = HttpClientBuilder.create().build();
        HttpGet request = new HttpGet("http://www.google.com");
        try (CloseableHttpResponse response = client.execute(request)) {
            return response;
        }
    }
}

关于这种情况的 java 最佳做法是什么?

作用域是一个编译时概念,它控制源代码中名称的使用位置。来自 JLS

The scope of a declaration is the region of the program within which the entity declared by the declaration can be referred to using a simple name, provided it is visible (§6.4.1).

换句话说,它不适用于对象(这是一个 运行时间概念),仅适用于引用它们的变量(和其他命名元素)。

对于您的示例(假设没有 return),如果您尝试在 try 块之外使用变量 response,它不会编译:

try (CloseableHttpResponse response = client.execute(request)) {    
} 
System.out.println(response); // nope, compilation error

A return 语句评估给定的表达式(在本例中为变量),解析值(对 CloseableHttpResponse 对象的引用),复制该值,然后 returns 它,从堆栈中弹出当前方法堆栈帧并将执行返回给调用方法。

对于您的 try-with-resources 语句,实际的 return 操作之前是一个 finally 块,它在 response 引用的对象上调用 close()多变的。据推测,这会使对象处于某种无法使用的状态。您可能会得到 运行 时间异常,具体取决于您随后如何使用它(即在接收 return 值的方法中)。