在Java中安全关闭流

在Java中安全关闭流,java,stream,try-with-resources,Java,Stream,Try With Resources,我想使用Java的try-with-resources安全地完全关闭多个流。我不知道我要说的有多冗长。我想确保我的资源得到充分利用。我的代码是这样工作的: JSONObject json; URL url = new URL("http://example.com/api.json"); HttpURLConnection urlConn = (HttpURLConnection) url.openConnection(); urlConn.setRequestMethod("GET"); u

我想使用Java的try-with-resources安全地完全关闭多个流。我不知道我要说的有多冗长。我想确保我的资源得到充分利用。我的代码是这样工作的:

JSONObject json;

URL url = new URL("http://example.com/api.json");
HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
urlConn.setRequestMethod("GET");
urlConn.connect();
try (InputStream is = urlConn.getInputStream()) {
    try (InputStreamReader isr = new InputStreamReader(is)) {
        StringBuilder sb = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(isr)) {
            String inputStr;
            while ((inputStr = reader.readLine()) != null)
                sb.append(inputStr);

            json = new JSONObject(sb.toString());
        }
    }
}
我想知道这是不是太过分了,如果我能做到这一点:

//...
urlConn.connect();

StringBuilder sb = new StringBuilder();
try (BufferedReader reader = new BufferedReader(
        new InputStreamReader(urlConn.getInputStream()))) {
    String inputStr;
    while ((inputStr = reader.readLine()) != null)
        sb.append(inputStr);

    json = new JSONObject(sb.toString());
}

流在调用其close时关闭底层流,因此两者都可以。如果需要匿名创建的InputStreamReader作为try{}范围中的变量名,但不需要两个嵌套的try{},可以执行以下操作:

try (InputStream is = urlConn.getInputStream(); InputStreamReader isr = new InputStreamReader(is)) {

通常,
InputStreamReader
BufferedReader
和类似程序遵循包装器样式模式,在
close
上关闭底层流

不过,在某些情况下,这两种方法并不相同。如果外部包装器可以在构造期间引发异常,那么内部资源将不会关闭

在您的示例中,调用
newInputStreamReader(…)
实际上可能会引发错误(由于不支持的编码)。如果发生这种情况,则通过
urlConn.getInputStream()
方法创建的
InputStream
将保持挂起状态

如果您使用@Xabster的建议(源代码示例),并将这两个资源分别分配,则应确保即使外部资源失败,内部
InputStream
也会关闭

您肯定应该看看以下资源:

当您使用try with resources时,资源可以自动关闭。要自动关闭,资源必须在try中声明和初始化,如下所示。还可以在try中准备多个语句,如图所示

String oldContent = "";

try(BufferedReader reader = new BufferedReader(new FileReader("filePath")); 
    FileWriter writer = new FileWriter("filePath")) {
        
        String line = reader.readLine();
        while (null != line) {
            oldContent = String.valueOf(oldContent) + line + System.lineSeparator();
            line = reader.readLine();
        }

        writer.write("filePath");

    } catch (IOException e) {
            LOG.error(e.getMessage());
        }
    }