Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Java's try-with-resources catch errors or just exceptions?

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.

like image 755
AlikElzin-kilaka Avatar asked Nov 02 '16 11:11

AlikElzin-kilaka


People also ask

Does try with resources need catch or finally?

Note: A try -with-resources statement can have catch and finally blocks just like an ordinary try statement. In a try -with-resources statement, any catch or finally block is run after the resources declared have been closed.

Does try with resources Throw exception?

For try-with-resources, if an exception is thrown in a try block and in a try-with-resources statement, then the method returns the exception thrown in the try block. The exceptions thrown by try-with-resources are suppressed, i.e. we can say that try-with-resources block throws suppressed exceptions.

What is the advantage of using try with resources statement?

Benefits of using try-with-resources: More readable code and easy to write. Automatic resource management. Number of lines of code is reduced.

Does Java 8 support try resources?

It is possible, and in fact common, for a base class to implement AutoCloseable even though not all of its subclasses or instances will hold releasable resources.


4 Answers

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

finally blocks are run even when an Error is thrown.

like image 188
Thilo Avatar answered Oct 08 '22 01:10

Thilo


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.

like image 42
Nicolas Filotto Avatar answered Oct 08 '22 02:10

Nicolas Filotto


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.
}
like image 13
Andy Turner Avatar answered Oct 08 '22 02:10

Andy Turner


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

like image 8
Raman Sahasi Avatar answered Oct 08 '22 02:10

Raman Sahasi