54

I have some junit tests which create some resources which should also be closed.

One way to implement this logic is using the @Before and @After approach.

What I did was to encapsulate the creation in some utility class to be reused. For example:

class UserCreatorTestUtil implements AutoClosable {
  User create() {...}
  void close() {...}
}

The whole point is for the object to close itself, rather than needing to remember to close it in @After.

The usage should be:

@Test
void test() {
  try (UserCreatorTestUtil userCreatorTestUtil = new UserCreatorTestUtil()) {
    User user = userCreatorTestUtil.create();
    // Do some stuff regarding the user's phone
    Assert.assertEquals("123456789", user.getPhone());
  }
}

The problem is that junit's assert keyword throws an Error - not Exception.

Will the try-with-resource "catch" the Error and invoke the close method?

* Couldn't find the answer in the try-with-resources documentation.

AlikElzin-kilaka
  • 34,335
  • 35
  • 194
  • 277
  • 9
    OT: Just for the records: *"I have some junit tests which create some resources"* so you don't have **UnitTests**, what you have are *Module Tests* using a *UnitTest -* **Framework**. – Timothy Truckle Nov 02 '16 at 12:02
  • 2
    @TimothyTruckle - while picking nits: *some resource* may just as well refer to a mocked out version, that still must be closed for everything to make sense. – Martin Ba Nov 02 '16 at 20:05
  • @MartinBa: In case of the TO the Tests are creating an closing resources. That's not what *I* call a UnitTest. Mocked recourses do not need to be closed (by the Test). The Test only needs to check that the production code called `close()` on them if needed... – Timothy Truckle Nov 02 '16 at 21:10
  • 1
    Both Errors and Exceptions (uppercase E) are kinds of exceptions (lowercase e). – user253751 Nov 03 '16 at 00:55
  • 1
    @immibis but we can call them Throwables to be case-insensitive and unambigious. – Thilo Nov 03 '16 at 10:38
  • 1
    @Thilo But case-insensitive languages are literally Satan. – user253751 Nov 03 '16 at 21:10

5 Answers5

73

It does not catch anything. But it does finally close all resources.

finally blocks are run even when an Error is thrown.

Community
  • 1
  • 1
Thilo
  • 257,207
  • 101
  • 511
  • 656
  • So I guess the answer is yes. It closes all resources because it behaves like in a finally block, which is called on any `Throwable`? – AlikElzin-kilaka Nov 02 '16 at 12:44
  • 1
    No, it simply doesn't know about any exceptions/errors. – Stephan Bijzitter Nov 02 '16 at 13:27
  • 2
    Yes, it does its cleanup in the same way a manual `finally` block would do. – Thilo Nov 02 '16 at 14:01
  • 5
    Note that finally works well except for `System.exit()`: http://stackoverflow.com/questions/14905006/system-exit-results-unexecutable-finally-block – Christophe Roussy Nov 02 '16 at 14:13
  • 12
    It behaves *almost* like a `finally` block, as, unlike a `finally` block, it will catch all subsequent `Throwable`s of the `close()` operations and add them as *suppressed* throwable to the primary throwable. A `finally` block can’t do that as it has no knowledage about the primary throwable, if there is one. – Holger Nov 02 '16 at 15:19
  • 2
    @Holger: Well, it is implemented as a `finally` block *in addition* to a `catch` block that does not really catch anything (just records the primary throwable and rethrows). All the "action" happens in the finally block. See @Nicolas answer for details. – Thilo Nov 03 '16 at 01:03
  • @Thilo: well, a combination of a `catch` block and a `finally` block still is something different than a `finally` block. That’s why I said “*almost like a finally block*”. But anyway, the pseudo code of Nicolas’ answer is only a formal specification and, as already said there in a comment, it makes not much sense to implement it literally that way, as, on the byte code level, there are no `finally` blocks; they are always implemented as an ordinary code path *and* a `catch` block code path and implementing try-with-resource as these two code paths in the first place would simplify the code. – Holger Nov 03 '16 at 10:11
37

The pseudo-code of a basic try-with-resources statement is (cf Java Language Specification §14.20.3.1):

final VariableModifiers_minus_final R Identifier = Expression;
Throwable #primaryExc = null;

try ResourceSpecification_tail
    Block
catch (Throwable #t) {
    #primaryExc = #t;
    throw #t;
} finally {
    if (Identifier != null) {
        if (#primaryExc != null) {
            try {
                Identifier.close();
            } catch (Throwable #suppressedExc) {
                #primaryExc.addSuppressed(#suppressedExc);
            }
        } else {
            Identifier.close();
        }
    }
}

As you can see it catches Throwable not Exception which includes Error but only to get the primary exception in order to add as suppressed exceptions any exceptions that occurred while closing the resources.

You can also notice that your resources are closed in the finally block which means that they will be closed whatever happens (except in case of a System.exit of course as it terminates the currently running Java Virtual Machine) even in case an Error or any sub class of Throwable is thrown.

Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122
  • 1
    Unfortunately, `javac` adheres literally to this convoluted formal specification. Considering, that `finally` is eventually implemented via code duplication for the two cases, it makes no sense at all, to store the exception in a variable and test it against `null`, when it is already implied by the code path whether there is an exception or not… – Holger Nov 02 '16 at 15:42
  • @Holger: Whether there was an exception or not is _not_ implied by the code path. Remember that the `finally` block is executed whether there was an exception or not. What code duplication do you mean (I guess the two `Identifier.close()`) and why does it annoy you? What would you suggest try-with-resources should do instead? – siegi Nov 08 '16 at 18:54
  • @siegi: on the byte code level, there is no `finally` feature, hence, a `finally` block is compiled by copying the action to every code path that could leave the block, plus an exception handler, i.e. `try { foo(); } finally { bar(); }` gets compiled to `try { foo(); } catch(Throwable t) { bar(); throw t; } bar();`, duplicating the `bar()` invocation code. There, it is implied by the code path whether an exception occurred or not, i.e. the first `bar();` invocation is the one under exceptional condition, the second is the one without. – Holger Nov 09 '16 at 09:10
  • @siegi: The code produced by `javac` as a consequence of this is discussed in [this question](http://stackoverflow.com/q/25615417/2711488). In my answer there, I referred to this behavior as “an artifact of how `javac` works internally”, without naming “implements this like a `finally` block” directly, simply because I didn’t know that formal specification at this point, but seeing it now, things become entirely clear (and the general statement still holds). – Holger Nov 09 '16 at 09:24
  • @Holger: Oh, I thought about code duplication at the Java language level (i.e. the snipped above) and not at the bytecode level. I guess it was a design decision to have no special case handling for try-with-resources in `javac` but to simply "desugar" it according to the language specification and then let the JIT compiler do its job. – siegi Nov 13 '16 at 08:27
13

Try-with-resources don't catch anything in and of themselves.

However, you can attach a catch block to the end of the try-with-resources block, to catch whatever types of Throwable you like:

try (UserCreatorTestUtil userCreatorTestUtil = new UserCreatorTestUtil()) {
  // ... Whatever
} catch (RuntimeException e) {
  // Handle e.
} catch (Exception | Throwable t) {
  // Handle t.
}
Andy Turner
  • 137,514
  • 11
  • 162
  • 243
8

The idea behind try-with-resources is to make sure that the resources should be closed.

The problem with conventional try-catch-finally statements is that let's suppose your try block throws an exception; now usually you'll handle that exception in finally block.

Now suppose an exception occurs in finally block as well. In such a case, the exception thrown by try catch is lost and the exception generated in finally block gets propagated.

try {
    // use something that's using resource
    // e.g., streams
} catch(IOException e) {
   // handle 
} finally {
    stream.close();
    //if any exception occurs in the above line, than that exception
    //will be propagated and the original exception that occurred
    //in try block is lost.
}

In try-with-resources the close() method of the resource will get automatically called, and if the close() throws any exception, the rest of the finally isn't reached, and the original exception is lost.

Contrast that with this:

try (InputStream inputStream= new FileInputStream("C://test.txt")){
    // ... use stream
} catch(IOException e) {
   // handle exception
}

in the above code snippet, the close() method automatically gets called and if that close() method also generated any exception, than that exception will automatically get suppressed.

See also: Java Language Specification 14.20.3

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Raman Sahasi
  • 30,180
  • 9
  • 58
  • 71
4

Misconception on your end: try-with-resources does not do a catch.

It does a final finally, therefore the kind of "problem" doesn't matter.

See the JLS for further information!

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • But it does do a catch, so that it can preserve the original exception, if any, and add subsequent exceptions as suppressed exceptions. – Mark Rotteveel Nov 03 '16 at 07:46