post-images/try-finally-vs-try-with-resources/cover.jpg

try-finally vs try-with-resources

Greetings 🙋🏻‍♂️ Today we will be discussing the last item of Creating and Destroying Objects, the first unit of Effective Java.

In this article, we will talk about the manual close method requirement found in most of the java libraries (InputStream, OutputStream etc.) and we will look for the right way to meet this requirement in the most correct way.

If we talk about the try-finally we use to close any file. When we did a retrospective analysis, it seemed like the best way to close a file (including throwing an in-scope exception). Because otherwise the finalize() method couldn't handle it. (Detailed information: Don't use finalize() and Cleaner! ) Let me share with you an example of using try-finally and talk about it .

// try-finally - No longer the best way to close resources!
static String firstLineOfFile(String path) throws IOException {
    BufferedReader br = new BufferedReader(new FileReader(path));
    try {
        return br.readLine();
    } finally {
        br.close();
    }
}

It doesn't look bad, does it? So what happens when another source that needs to be shut down is involved?

// try-finally is ugly when used with more than one resource!
static void copy(String src, String dst) throws IOException {
    InputStream in = new FileInputStream(src);
    try {
        OutputStream out = new FileOutputStream(dst);
        try {
            byte[] buf = new byte[BUFFER_SIZE];
            int n;
            while ((n = in .read(buf)) >= 0) out.write(buf, 0, n);
        } finally {
            out.close();
        }
    } finally { in .close();
    }
}

Nested try methods etc. How about you seem a little confused? In fact, there is no logical error in the mechanism we have established. The fact that this method can throw exceptions, which we mentioned as an advantage, it made try-finally obsolete and deprecated it with try-with-resources that came with java 7. So what is this event? The thing is exactly this: You can get an exception in try, for example, an error may occur in the file for some reason in the readLine() method call. As a result of this error, of course, an exception will be thrown as the finally step cannot close the file. We have two exceptions. The exception thrown in try will be override by the exception thrown in finally, even though the basic reasons are the same. This override process will make it difficult for the developer to view the stack trace containing the information about the source of the problem and to solve the source problem.

In my previous article, I gave the spoiler that try-with-resources is the most guaranteed method for a process to be terminated completely. So what is try-with-resources? How to use? Let me answer with an example.

// try-with-resources - the best way to close resources!
static String firstLineOfFile(String path) throws IOException {
    try (BufferedReader br = new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
}

By the way, let me add an extra source to be closed like the previous example, and then I'll reply.

// try-with-resources on multiple resources - short and sweet
static void copy(String src, String dst) throws IOException {
    try (InputStream in = new FileInputStream(src);
        OutputStream out = new FileOutputStream(dst)) {
        byte[] buf = new byte[BUFFER_SIZE];
        int n;
        while ((n = in .read(buf)) >= 0) {
            out.write(buf, 0, n);
        }
    }

}

First of all, it caught your eye that there is no nested try structure, right? How simple, clean and readable it looks. By the way, let me mention here that in case you want to use try-with-resources, you need to inherit your class from AutoClosable class. The void close() method in it is called automatically and performs the aforementioned closing operations.

I seem to feel you're thinking what about the exception event in try-with-resources. In the try-with-resources structure, an exception can be thrown inside the try, or in the automatically triggered close() method from the AutoClosable class. The obvious difference with try-finally here is that the first exception that points to the source of the real problem is printed on the stack trace, not the last exception thrown. It even has a beauty that if more than two exceptions are encountered, all exceptions are suppressed except the one that points to the source. You can access these silenced exceptions with getSuppressed method by impelement Throwable.

It is not included in the above example, but it is possible to add a 'catch' mechanism in 'try-with-resources', just like in 'try-finally'.

// try-with-resources with a catch clause
static String firstLineOfFile(String path, String defaultVal) {
    try (BufferedReader br = new BufferedReader(new FileReader(path))) {
        return br.readLine();
    } catch (IOException e) {
        return defaultVal;
    }
}

In summary, for any resource you want to ensure that it is shut down, not memory leaked, or has no problems with exceptions, choose try-with-resources as used in java's own libraries.

Ciao Bella 💃🏻

JavaEffective JavaCreating and Destroying Objectstry-finallytry-with-resourcesInputStreamOutputStream