Corey
Corey

Reputation: 123

Closing streams safely in Java

I want to safely, fully close multiple streams using Java's try-with-resources. I don't know how verbose I have to be. I want to make sure my resources are fully disposed of. My code works like this:

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());
        }
    }
}

I'm wondering if this is overkill, and if I can do this:

//...
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());
}

Upvotes: 0

Views: 178

Answers (3)

Achu22
Achu22

Reputation: 376

When you use try with resources, resources are auto closable. To be auto-closed, a resource must be both declared and initialized inside the try, as shown below. Also multiple statements can be prepared inside try as shown.

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());
        }
    }

Upvotes: 0

Momchil Atanasov
Momchil Atanasov

Reputation: 518

In general, InputStreamReader, BufferedReader and similar follow a wrapper style pattern where they close the underlying stream on close.

There are cases when the two approaches are not the same, though. If the outer wrapper can throw an exception during construction, then the inner resource will not get closed.

In your example, the call to new InputStreamReader(...) can actually throw an error (due to unsupported encoding). If that happens, then the InputStream that was created via the urlConn.getInputStream() method would be left hanging.

If you use the proposal (source example) of @Xabster and have both resources allocated separately, this should assure that the inner InputStream is closed even if the outer one fails.

You should definitely have a look at the following resource: http://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html

Upvotes: 1

Xabster
Xabster

Reputation: 3720

Streams close the underlying streams when their close is called, so both are fine. If you need the anonymously created InputStreamReader as a variable name in the try { } scope, but you don't want 2 nested try { }'s, you can do:

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

Upvotes: 0

Related Questions