What's the purpose of try-with-resources statements?

Solution 1:

It was introduced because of some resources used in Java (like SQL connections or streams) being difficult to be handled properly; as an example, in java 6 to handle a InputStream properly you had to do something like:

InputStream stream = new MyInputStream(...);
try {
    // ... use stream
} catch(IOException e) {
   // handle exception
} finally {
    try {
        if(stream != null) {
            stream.close();
        }
    } catch(IOException e) {
        // handle yet another possible exception
    }
}

Do you notice that ugly double try? now with try-with-resources you can do this:

try (InputStream stream = new MyInputStream(...)){
    // ... use stream
} catch(IOException e) {
   // handle exception
}

and close() is automatically called, if it throws an IOException, it will be supressed (as specified in the Java Language Specification 14.20.3) . Same happens for java.sql.Connection

Solution 2:

As stated in the documentation:

The try-with-resources statement is a try statement that declares one or more resources. A resource is an object that must be closed after the program is finished with it. The try-with-resources statement ensures that each resource is closed at the end of the statement. Any object that implements java.lang.AutoCloseable, which includes all objects which implement java.io.Closeable, can be used as a resource.

The following example reads the first line from a file. It uses an instance of BufferedReader to read data from the file. BufferedReader is a resource that must be closed after the program is finished with it:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

In this example, the resource declared in the try-with-resources statement is a BufferedReader. The declaration statement appears within parentheses immediately after the try keyword. The class BufferedReader, in Java SE 7 and later, implements the interface java.lang.AutoCloseable. Because the BufferedReader instance is declared in a try-with-resource statement, it will be closed regardless of whether the try statement completes normally or abruptly

You can read more from here.

Solution 3:

Update from 2017 after Java 9 release

Now with Java 9 we have more syntactic sugar and we can have a resource declared outside the try-catch block but still handled properly.

Let's take for example this Java 6 way of handling the resource:

InputStream stream = new MyInputStream(...);
try {
    // ... use stream
} catch(IOException e) {
   // handle exception
} finally {
    try {
        if(stream != null) {
            stream.close();
        }
    } catch(IOException e) {
        // handle yet another possible exception
    }
}

Here we can notice that this code is incredibly ugly as pointed out in other answers.

So the solution in Java 7 was to introduce this try-catch-with-resource:

try (InputStream stream = new MyInputStream(...)){
    // ... use stream
} catch(IOException e) {
   // handle exception
}

This notation is surely way better than the previous one, however we have a problem. If the resource (stream in this case) has been declared previously but we want to be sure that it's handled correctly in this block we need a trick like this:

InputStream stream = new MyInputStream(...)
try (InputStream stream2 = stream) {
   // do something with stream being sure that is going to be closed at the end
} catch(IOException e) {
   // handle exception
}

We can notice that this situation can be addressed only with another piece of ugly code. That's why with Java 9 the Try-With-Resources has been improved introducing a new syntax:

InputStream stream = new MyInputStream(...)
try (stream) {
   // do something with stream being sure that is going to be closed at the end
} catch(IOException e) {
   // handle exception
}

Note that this syntax will result in a compile time error for Java version 8 or minor

This is more "natural" way of writing even though in most use cases we don't need the resource outside the scope of the try block. The only restriction is that the reader variable should be effectively final or just final.

Solution 4:

In Java, if you use a resource like input or output streams you always have to close it after using. It also can throw exceptions so it has to be in a try catch block. The closing has to be in the finally block. This is a least the way until Java 7. This has several disadvantages:

  • You'd have to check if your ressource is null before closing it
  • The closing itself can throw exceptions so your finally had to contain another try - catch
  • Programmers tend to forget to close their ressources

While the first two are mostly syntax issues, the last one is more critical. So if you use the try-with statement your code gets a lot cleaner and most importantly: Your ressource will always be closed :-)