loading...

Effective Java Tuesday! Prefer try-with-resources

kylec32 profile image Kyle Carter ・3 min read

Effective Java Review (36 Part Series)

1) Effective Java Tuesday! Let's Consider Static Factory Methods 2) Effective Java Tuesday! The Builder Pattern! 3 ... 34 3) Effective Java Tuesday! Singletons! 4) Effective Java Tuesday! Utility Classes! 5) Effective Java Tuesday! Prefer Dependency Injection! 6) Effective Java Tuesday! Avoid Creating Unnecessary Objects! 7) Effective Java Tuesday! Don't Leak Object References! 8) Effective Java Tuesday! Avoid Finalizers and Cleaners! 9) Effective Java Tuesday! Prefer try-with-resources 10) Effective Java Tuesday! Obey the `equals` contract 11) Effective Java Tuesday! Obey the `hashCode` contract 12) Effective Java Tuesday! Override `toString` 13) Effective Java Tuesday! Override `clone` judiciously 14) Effective Java Tuesday! Consider Implementing `Comparable` 15) Effective Java Tuesday! Minimize the Accessibility of Classes and Member 16) Effective Java Tuesday! In Public Classes, Use Accessors, Not Public Fields 17) Effective Java Tuesday! Minimize Mutability 18) Effective Java Tuesday! Favor Composition Over Inheritance 19) Effective Java Tuesday! Design and Document Classes for Inheritance or Else Prohibit It. 20) Effective Java Tuesday! Prefer Interfaces to Abstract Classes 21) Effective Java! Design Interfaces for Posterity 22) Effective Java! Use Interfaces Only to Define Types 23) Effective Java! Prefer Class Hierarchies to Tagged Classes 24) Effective Java! Favor Static Members Classes over Non-Static 25) Effective Java! Limit Source Files to a Single Top-Level Class 26) Effective Java! Don't Use Raw Types 27) Effective Java! Elminate Unchecked Warnings 28) Effective Java! Prefer Lists to Array 29) Effective Java! Favor Generic Types 30) Effective Java! Favor Generic Methods 31) Effective Java! Use Bounded Wildcards to Increase API Flexibility 32) Effective Java! Combine Generics and Varargs Judiciously 33) Effective Java! Consider Typesafe Hetergenous Containers 34) Effective Java! Use Enums Instead of int Constants 35) Effective Java! Use Instance Fields Instead of Ordinals 36) Effective Java! Use EnumSet Instead of Bit Fields

Today we have a topic right in line with what we talked about last week. Last week the topic was on finalizers and cleaners. One of the common uses for these is to clean up resources. In this blog post we will go into a little more detail of the better way we hinted at at the end of the previous post.

There are many resources that for one reason or another need to be manually closed after use. This often is accomplished by using a close method on the object. We of course don't want to leak resources or leave items in a half handled state. This being the case we may consider putting the close method in a finally block. For example:

static List<Object> getDbValues() {
  EntityManager em = getEntityManager();
  try {
    return em.createNativeQuery("SELECT * FROM myTable").getResultsList();
  } finally {
    em.close();
  }
}

This will work just fine, it doesn't even look that bad. It does get more confusing and error prone as we add more resources.

static List<Object> getDbValues() {
  OutputStream output = getOutputStream();
  InputStream input = getInputstream();
  try {
    try {
      // do work
    } finally {
      input.close();
    }
  } finally {
    output.close();
  }
}

This is starting to get more gross and hard to follow. Did I even do it right? I'm not convinced. It can be easy to mess up. The author even admits that he had this pattern messed up in one of his books for years and no one realized. Even with the correct code there are subtleties with error handling that are not handled as well as they could. Exceptions can override each other and we could lose valuable information in the stack traces that occur. You could write code to handle this but it's complex and ugly thus no one wrote it that way.

So in Java 7 we got our better answer, try-with-resources. With this construct any class that implements AutoCloseable can have it's closing handled by Java. Thus are above example looks like:

try(InputStream input = new FileInputStream("file");
    OutputStream output = new FileOutputStream("other")) {
            // do work
}

This is much simpler. It also handles a lot more than we were handling in our previous example. This is not actually how the code stays. The above code gets transformed by the compiler into a much more verbose result. Let's take a look:

InputStream input = new FileInputStream("file");
Throwable var2 = null;

try {
    OutputStream output = new FileOutputStream("other");
    Throwable var4 = null;

    try {
        //do work
    } catch (Throwable var27) {
        var4 = var27;
        throw var27;
    } finally {
        if (output != null) {
            if (var4 != null) {
                try {
                    output.close();
                } catch (Throwable var26) {
                    var4.addSuppressed(var26);
                }
            } else {
                output.close();
            }
        }

    }
} catch (Throwable var29) {
    var2 = var29;
    throw var29;
} finally {
    if (input != null) {
        if (var2 != null) {
            try {
                input.close();
            } catch (Throwable var25) {
                var2.addSuppressed(var25);
            }
        } else {
            input.close();
        }
    }

}

Whoa! That got pretty intense. But if you parse through it you can see that it is doing the work we were hoping while handling exceptions much more completely.

Final thought. In a previous post I mentioned the tool Lombok. I very much think this is a good tool. Inside the bag of tricks of Lombok there is an annotation @Cleanup. It looks like it will do something very similar to the above. So what makes these two different. While it is correct that they do similar things they do have a slight different. The main difference is that @Cleanup simply writes the try-finally combinations like we did above but doesn't do any magic handling the exception handling. So while @Cleanup does give us the safety of a finally block we do lose the specialized exception handling.

So there you have it. Use try-with-resources. It's easier, it's cleaner, is safer, this is truly a place where I don't see a lot of downsides.

Effective Java Review (36 Part Series)

1) Effective Java Tuesday! Let's Consider Static Factory Methods 2) Effective Java Tuesday! The Builder Pattern! 3 ... 34 3) Effective Java Tuesday! Singletons! 4) Effective Java Tuesday! Utility Classes! 5) Effective Java Tuesday! Prefer Dependency Injection! 6) Effective Java Tuesday! Avoid Creating Unnecessary Objects! 7) Effective Java Tuesday! Don't Leak Object References! 8) Effective Java Tuesday! Avoid Finalizers and Cleaners! 9) Effective Java Tuesday! Prefer try-with-resources 10) Effective Java Tuesday! Obey the `equals` contract 11) Effective Java Tuesday! Obey the `hashCode` contract 12) Effective Java Tuesday! Override `toString` 13) Effective Java Tuesday! Override `clone` judiciously 14) Effective Java Tuesday! Consider Implementing `Comparable` 15) Effective Java Tuesday! Minimize the Accessibility of Classes and Member 16) Effective Java Tuesday! In Public Classes, Use Accessors, Not Public Fields 17) Effective Java Tuesday! Minimize Mutability 18) Effective Java Tuesday! Favor Composition Over Inheritance 19) Effective Java Tuesday! Design and Document Classes for Inheritance or Else Prohibit It. 20) Effective Java Tuesday! Prefer Interfaces to Abstract Classes 21) Effective Java! Design Interfaces for Posterity 22) Effective Java! Use Interfaces Only to Define Types 23) Effective Java! Prefer Class Hierarchies to Tagged Classes 24) Effective Java! Favor Static Members Classes over Non-Static 25) Effective Java! Limit Source Files to a Single Top-Level Class 26) Effective Java! Don't Use Raw Types 27) Effective Java! Elminate Unchecked Warnings 28) Effective Java! Prefer Lists to Array 29) Effective Java! Favor Generic Types 30) Effective Java! Favor Generic Methods 31) Effective Java! Use Bounded Wildcards to Increase API Flexibility 32) Effective Java! Combine Generics and Varargs Judiciously 33) Effective Java! Consider Typesafe Hetergenous Containers 34) Effective Java! Use Enums Instead of int Constants 35) Effective Java! Use Instance Fields Instead of Ordinals 36) Effective Java! Use EnumSet Instead of Bit Fields

Posted on by:

kylec32 profile

Kyle Carter

@kylec32

Backend Architect at MasterControl

Discussion

markdown guide