Question

Suppose I have a lazy iterable instance which requires closing to free resources. If I return this from a method and close it in a finally block, will the finally block be invoked before or after it is consumed by the client?

For example:

public CloseableIterable<T> getStuff() {
    CloseableIterable<T> iterable = fetchStuffFromSomewhere();
    try {
        return iterable;
    } finally {
        iterable.close();
    }
}

Note: on Java 6 here, but I'd also be interested in how the try-with-resources bits in Java 7 would handle this case.

Was it helpful?

Solution

The finally block will always execute before the try block is considered finished.

According to the JLS, Section 14.17, a return statement

attempts to transfer control to the invoker of the method that contains it;

and

The preceding descriptions say "attempts to transfer control" rather than just "transfers control" because if there are any try statements (§14.20) within the method or constructor whose try blocks or catch clauses contain the return statement, then any finally clauses of those try statements will be executed, in order, innermost to outermost, before control is transferred to the invoker of the method or constructor. Abrupt completion of a finally clause can disrupt the transfer of control initiated by a return statement.

(bold emphasis mine)

That is, a return statement inside a try will execute the finally block before actually returning. Therefore, your CloseableIterable will be closed before it gets returned to the caller.

As for "try-with-resources", the code is equivalent to a try-catch-finally block, so it should behave the same. According to the JLS, Section 14.20.3,

A try-with-resources statement is parameterized with variables (known as resources) that are initialized before execution of the try block and closed automatically, in the reverse order from which they were initialized, after execution of the try block.

That is, the equivalent code you've written above with "try-with-resources" in Java 1.7 would be:

try (CloseableIterable<T> iterable = fetchStuffFromSomewhere()) {
    return iterable;
}

... and it would still close it before control is transferred back to the method's caller.

OTHER TIPS

The finally block is executed right before the return statement. You will have to let the client code of the method handle the iterable instance correctly (make it part of your method contract and document it properly).

Also, it would be worth to learn by example. Go find a method in Java API that returns a Closeable and then go to its source code and see how it's handled.

I would use a Consumer here:

public void forEachItemInStuff(Consumer<T> consumer) {
    CloseableIterable<T> iterable = fetchStuffFromSomewhere();
    try {
        for(T t:iterable) {
            consumer.accept(t);
        }
    } finally {
        iterable.close();
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top