Reduce nesting when cleaning up multiple non-Closeable resources - java

I have a Closeable that needs to clean up multiple resources in the close() method. Each resource is a final class that I cannot modify. None of the included resources are Closeable or AutoCloseable. I also need to call super.close(). So it appears that I cannot handle any of the resources* using try-with-resources. My current implementation looks something like this:
public void close() throws IOException {
try {
super.close();
} finally {
try {
container.shutdown();
} catch (final ShutdownException e) {
throw new IOException("ShutdownException: ", e);
} finally {
try {
client.closeConnection();
} catch (final ConnectionException e) {
throw new IOException("Handling ConnectionException: ", e);
}
}
}
}
I'd prefer a solution with less crazy nesting but I can't figure out how to take advantage of try-with-resources or any other features to do that. Code sandwiches don't seem to help here since I'm not using the resources at all, just cleaning them up. Since the resources aren't Closeable, it's unclear how I could use the recommended solutions in Java io ugly try-finally block.
* Even though the super class is Closeable, I cannot use super in a try-with-resources because super is just syntactic sugar and not a real Java Object.

This a good (albeit unorthodox) case for try-with-resources. First, you'll need to create some interfaces:
interface ContainerCleanup extends AutoCloseable {
#Override
void close() throws ShutdownException;
}
interface ClientCleanup extends AutoCloseable {
#Override
void close() throws ConnectionException;
}
If these interfaces are only used in the current class, I'd recommend making them inner interfaces. But they also work as public utility interfaces if you use them in multiple classes.
Then in your close() method you can do:
public void close() throws IOException {
final Closeable ioCleanup = new Closeable() {
#Override
public void close() throws IOException {
YourCloseable.super.close();
}
};
final ContainerCleanup containerCleanup = new ContainerCleanup() {
#Override
public void close() throws ShutdownException {
container.shutdown();
}
};
final ClientCleanup clientCleanup = new ClientCleanup() {
#Override
public void close() throws ConnectionException {
client.closeConnection();
}
};
// Resources are closed in the reverse order in which they are declared,
// so reverse the order of cleanup classes.
// For more details, see Java Langauge Specification 14.20.3 try-with-resources:
// https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.20.3
try (clientCleanup; containerCleanup; ioCleanup) {
// try-with-resources only used to ensure that all resources are cleaned up.
} catch (final ShutdownException e) {
throw new IOException("Handling ShutdownException: ", e);
} catch (final ConnectionException e) {
throw new IOException("Handling ConnectionException: ", e);
}
}
Of course this becomes even more elegant and concise with Java 8 lambdas:
public void close() throws IOException {
final Closeable ioCleanup = () -> super.close();
final ContainerCleanup containerCleanup = () -> container.shutdown();
final ClientCleanup clientCleanup = () -> client.closeConnection();
// Resources are closed in the reverse order in which they are declared,
// so reverse the order of cleanup classes.
// For more details, see Java Langauge Specification 14.20.3 try-with-resources:
// https://docs.oracle.com/javase/specs/jls/se8/html/jls-14.html#jls-14.20.3
try (clientCleanup; containerCleanup; ioCleanup) {
// try-with-resources only used to ensure that all resources are cleaned up.
} catch (final ShutdownException e) {
throw new IOException("Handling ShutdownException: ", e);
} catch (final ConnectionException e) {
throw new IOException("Handling ConnectionException: ", e);
}
}
This removes all the crazy nesting and it has the added benefit of saving the suppressed exceptions. In your case, if client.closeConnection() throws, we'll never know if the previous methods threw any exceptions. So the stacktrace will look something like this:
Exception in thread "main" java.io.IOException: Handling ConnectionException:
at Main$YourCloseable.close(Main.java:69)
at Main.main(Main.java:22)
Caused by: Main$ConnectionException: Failed to close connection.
at Main$Client.closeConnection(Main.java:102)
at Main$YourCloseable.close(Main.java:67)
... 1 more
By using try-with-resources, the Java compiler generates code to handle the suppressed exceptions, so we'll see them in the stacktrace and we can even handle them in the calling code if we want to:
Exception in thread "main" java.io.IOException: Failed to close super.
at Main$SuperCloseable.close(Main.java:104)
at Main$YourCloseable.access$001(Main.java:35)
at Main$YourCloseable $1.close(Main.java:49)
at Main$YourCloseable.close(Main.java:68)
at Main.main(Main.java:22)
Suppressed: Main$ShutdownException: Failed to shut down container.
at Main$Container.shutdown(Main.java:140)
at Main$YourCloseable$2.close(Main.java:55)
at Main$YourCloseable.close(Main.java:66)
... 1 more
Suppressed: Main$ConnectionException: Failed to close connection.
at Main$Client.closeConnection(Main.java:119)
at Main$YourCloseable$3.close(Main.java:61)
at Main$YourCloseable.close(Main.java:66)
... 1 more
Caveats
If the order of clean up matters, you need to declare your resource cleanup classes/lambdas in the reverse order that you want them run. I recommend adding a comment to that effect (like the one I provided).
If any exceptions are suppressed, the catch block for that exception will not execute. In those cases, it's probably better change the lambdas to handle the exception:
final Closeable containerCleanup = () -> {
try {
container.shutdown();
} catch (final ShutdownException e) {
// Handle shutdown exception
throw new IOException("Handling shutdown exception:", e);
}
}
Handling the exceptions inside the lambda does start to add some nesting, but the nesting isn't recursive like the original so it'll only ever be one level deep.
Even with those caveats, I believe the pros greatly outweigh the cons here with the automatic suppressed exception handling, conciseness, elegance, readability, and reduced nesting (especially if you have 3 or more resources to clean up).

Related

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.
It does not catch anything. But it does finally close all resources.
finally blocks are run even when an Error is thrown.
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.
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.
}
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
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!

Android Java - how to refactor out a try-catch-finally with a throw in the finally, all inside an abstract class?

Good afternoon,
I'm currently working with the code from:
https://github.com/kevinsawicki/http-request
I'm attempting to refactor the code as applicable to clear all the Android Studio warnings before I include it in a project I'm working on. Currently I'm working with the following nested abstract class:
///////////////////////////////////////////////////////////////////////////////////////////////
protected static abstract class Operation<V> implements Callable<V> {
protected abstract V run() throws HttpRequestException, IOException;
protected abstract void done() throws IOException;
public V call() throws HttpRequestException {
Log.d(TAG, "in HttpRequest nested class Operation call");
boolean thrown = false;
try {
return run();
} catch (HttpRequestException e) {
thrown = true;
throw e;
} catch (IOException e) {
thrown = true;
throw new HttpRequestException(e);
} finally {
try {
done();
} catch (IOException e) {
if (!thrown) {
throw new HttpRequestException(e);
}
}
}
}
} // end Operation
This is producing the following warning for having a throw inside a finally block:
I've been looking at this for a while but I can't seem to find a way to factor out this warning. I did see this other answer:
throws Exception in finally blocks
However I would really prefer to not introduce another function. If I was to introduce a closeQuietly function, would that go inside or outside the nested class listed above? Please advise, thanks!
It's just a warning. If you read the explanation it says (emphasis mine)
While occasionally intended, such throw statements may mask exceptions thrown and tremendously complicate debugging.
If you need to do it, then do it, but just make sure it's actually what you want to do and understand the implications (it's akin to saying "do you really want to do this?!"). Not all of IntelliJ's warnings can be eliminated.
Edit based on follow up: You have to ask yourself if your framework needs to throw that exception in the finally block. You can implement a similar approach to what was linked without using another function (just replace the throw statement in finally with a log statement), but that might not be desirable. It depends entirely on the potential error conditions.
If, for example, you're expecting done() to run into issues whenever you've previously received an IOException or an HttpRequestException then you probably don't need to throw anything in the finally block (just log it). But, if you need to make sure you alert the user if something went wrong trying to clean up, then you do need to throw there and you should ignore the warning.
I suppose you could do something like this:
protected static abstract class Operation<V> implements Callable<V> {
protected abstract V run() throws HttpRequestException, IOException;
protected abstract void done() throws IOException;
public V call() throws HttpRequestException {
Log.d(TAG, "in HttpRequest nested class Operation call");
boolean thrown = false;
try {
return run();
} catch (IOException e) {
throw new HttpRequestException(e);
} finally {
try {
done();
} catch (IOException e) {
// handle the IOException
}
}
}
} // end Operation
If an HttpRequestException is ever thrown it'll be thrown by the method, you still transform the IOException into an HttpRequestException (not quite sure why you want to do that), and in the finally block you would need to catch and handle the IOException appropriately.

How to make sure resource is released, with nested object hierarchy?

I have code (simplified) like this:
class A {
B b = new B();
void close() {
b.close();
}
}
class B {
Closeable mustBeClosed = new Closeable() {
{
System.out.println("create");
}
#Override
public void close() {
System.out.println("close");
}
};
int n = 0 / 0;
void close() {
mustBeClosed.close();
}
}
//code
try (A a = new A()) {
//do something
}
How to guarantee mustBeClosed is released?
This likely happens when the object hierarchy is complex. Override finalize for B might not be a perfect solution.
Any best practice or principle against this issue?
A revised version looks like:
class B {
Closeable mustBeClosed;
B() {
try {
mustBeClosed = ...
//other initialization which might raise exceptions
} catch (throwable t) {
close();
throw t;
}
}
void close() {
if (mustBeClosed != null) {
try {
mustBeClosed.close();
} catch (Throwable t) {
}
}
//all other resources that should be closed
}
}
However this takes too much code and is far from elegant. What's more, it seems that all classes in the ownership hierarchy should follow the same style, which results lots of code.
Any advice?
Your problem is that try-with-resources won't (actually can't) call close() if the constructor throws an exception.
Any object construction that allocates a resource, and has the potential to fail during construction after the resource is allocated, must release that resource before the exception is cascaded up the call stack.
Two ways to fix that:
1) Make sure the resource allocation is the last action performed. In your case, that means move field n up before field mustBeClosed.
2) Handle the resource construction in the constructor, not in a field initializer, so you can catch any subsequent exception and release the resource again before re-throwing the exception, as your alternate solution shows.
However, you don't have to null-check in the close() method, because mustBeClosed will always be non-null if the object construction succeeds, and close() cannot be called if the object construction fails.
Use a wrapper method to close all Closeable instances gracefully.
closeGraceFully(Closeable c) { // call this guy for all instances of closeable
try{
c.close();
} catch(IOException ex) {
// nothing can be done here, frankly.
}
}
Then call this wrapper method. don't call close() directly. Don't use finalizers they are evil and will slow down your app.

Java 8: How do I work with exception throwing methods in streams?

Suppose I have a class and a method
class A {
void foo() throws Exception() {
...
}
}
Now I would like to call foo for each instance of A delivered by a stream like:
void bar() throws Exception {
Stream<A> as = ...
as.forEach(a -> a.foo());
}
Question: How do I properly handle the exception? The code does not compile on my machine because I do not handle the possible exceptions that can be thrown by foo(). The throws Exception of bar seems to be useless here. Why is that?
You need to wrap your method call into another one, where you do not throw checked exceptions. You can still throw anything that is a subclass of RuntimeException.
A normal wrapping idiom is something like:
private void safeFoo(final A a) {
try {
a.foo();
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
(Supertype exception Exception is only used as example, never try to catch it yourself)
Then you can call it with: as.forEach(this::safeFoo).
If all you want is to invoke foo, and you prefer to propagate the exception as is (without wrapping), you can also just use Java's for loop instead (after turning the Stream into an Iterable with some trickery):
for (A a : (Iterable<A>) as::iterator) {
a.foo();
}
This is, at least, what I do in my JUnit tests, where I don't want to go through the trouble of wrapping my checked exceptions (and in fact prefer my tests to throw the unwrapped original ones)
This question may be a little old, but because I think the "right" answer here is only one way which can lead to some issues hidden Issues later in your code. Even if there is a little Controversy, Checked Exceptions exist for a reason.
The most elegant way in my opinion can you find was given by Misha here Aggregate runtime exceptions in Java 8 streams
by just performing the actions in "futures". So you can run all the working parts and collect not working Exceptions as a single one. Otherwise you could collect them all in a List and process them later.
A similar approach comes from Benji Weber. He suggests to create an own type to collect working and not working parts.
Depending on what you really want to achieve a simple mapping between the input values and Output Values occurred Exceptions may also work for you.
If you don't like any of these ways consider using (depending on the Original Exception) at least an own exception.
You might want to do one of the following:
propagate checked exception,
wrap it and propagate unchecked exception, or
catch the exception and stop propagation.
Several libraries let you do that easily. Example below is written using my NoException library.
// Propagate checked exception
as.forEach(Exceptions.sneak().consumer(A::foo));
// Wrap and propagate unchecked exception
as.forEach(Exceptions.wrap().consumer(A::foo));
as.forEach(Exceptions.wrap(MyUncheckedException::new).consumer(A::foo));
// Catch the exception and stop propagation (using logging handler for example)
as.forEach(Exceptions.log().consumer(Exceptions.sneak().consumer(A::foo)));
I suggest to use Google Guava Throwables class
propagate(Throwable throwable)
Propagates throwable as-is if it is an
instance of RuntimeException or Error, or else as a last resort, wraps
it in a RuntimeException and then propagates.**
void bar() {
Stream<A> as = ...
as.forEach(a -> {
try {
a.foo()
} catch(Exception e) {
throw Throwables.propagate(e);
}
});
}
UPDATE:
Now that it is deprecated use:
void bar() {
Stream<A> as = ...
as.forEach(a -> {
try {
a.foo()
} catch(Exception e) {
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
});
}
You can wrap and unwrap exceptions this way.
class A {
void foo() throws Exception {
throw new Exception();
}
};
interface Task {
void run() throws Exception;
}
static class TaskException extends RuntimeException {
private static final long serialVersionUID = 1L;
public TaskException(Exception e) {
super(e);
}
}
void bar() throws Exception {
Stream<A> as = Stream.generate(()->new A());
try {
as.forEach(a -> wrapException(() -> a.foo())); // or a::foo instead of () -> a.foo()
} catch (TaskException e) {
throw (Exception)e.getCause();
}
}
static void wrapException(Task task) {
try {
task.run();
} catch (Exception e) {
throw new TaskException(e);
}
}
More readable way:
class A {
void foo() throws MyException() {
...
}
}
Just hide it in a RuntimeException to get it past forEach()
void bar() throws MyException {
Stream<A> as = ...
try {
as.forEach(a -> {
try {
a.foo();
} catch(MyException e) {
throw new RuntimeException(e);
}
});
} catch(RuntimeException e) {
throw (MyException) e.getCause();
}
}
Although at this point I won't hold against someone if they say skip the streams and go with a for loop, unless:
you're not creating your stream using Collection.stream(), i.e. not straight forward translation to a for loop.
you're trying to use parallelstream()

performing clean up and passing the exception to the caller

I need to do some initialization and clean it up in case of any exception. I'd still like the exception to be passed to the caller. The problem is I now have to declare this method as throws Throwable and then I have to explicitly handle this throwable in the caller, just as if all procedures don't throw Throwables implicitly already. Stupid isn't it?
try {
init_step1();
init_step2();
}
catch (Throwable th) {
clean();
throw th;
}
One way of doing this is to perform the cleanup in a finally block instead, noticing whether there's been an exception by whether you actually got to the end of the try block or not:
boolean success = false;
try {
// Stuff here
success = true;
} finally {
if (!success) {
clean();
}
}
Stupid is fighting against checked exceptions. You have to throw something different if you don't want to require every caller to handle it. just throw a RuntimeException
public void myMethod() throws RuntimeException {
try {
init_step1();
init_step2();
}
catch (Throwable th) {
clean();
throw new RuntimeException(th);
}
}
why do you catch Throwable in first place anyway? init_step1() and init_step2() doesn't throw an exception?
#Jon Skeet's solution is the cleanest. Another solution which may interest you.
try {
// Stuff here
} catch(Throwable t) {
clean(t);
// bypasses the compiler check
Thread.currentThread().stop(t);
}
I would only suggest using this approach if you needed to know the exception thrown. e.g. For resources I have which are closable, I record the exception which triggered their close. This way if I try to use the resource and it is closed I can see why it is closed.
private void checkClosed() {
if (closed)
throw new IllegalStateException("Closed", reasonClosed);
}

Categories