This post describes an approach to handling checked exceptions using Java 8 lambdas without adding try/catch blocks everywhere.
Lambdas and checked exceptions
Consider this contrived example:
import java.io.IOException; import java.io.UncheckedIOException; public class WrapAndUnwrap { private void runit(Runnable runner) { runner.run(); } private void throwit() throws IOException { throw new IOException("expected"); } /** * @throws IOException when an error occurs */ public void combine() throws IOException { try { runit(() -> { try { throwit(); } catch (IOException e) { throw new UncheckedIOException(e); } }); } catch (UncheckedIOException e) { throw e.getCause(); } } }
In order to have runit
invoke the throwit
method and meet the error handling contract for combine
the code must wrap and unwrap the IOException
.
Using KλudJe to handle checked exceptions
Here a cleaner way to implement the logic:
import uk.kludje.fn.lang.URunnable; import java.io.IOException; public class TransparentThrow { private void runit(Runnable runner) { runner.run(); } private void throwit() throws IOException { throw new IOException("expected"); } public void combine() throws IOException { runit((URunnable) this::throwit); } }
This code uses the KλudJe library which can be downloaded from the Central Repository. KλudJe contains mirror types for many of the standard API functional interfaces.
URunnable
The URunnable
type takes advantage of two things:
- "Sneaky throws"
- Default methods
Checked exceptions only matter to the Java compiler. Other JVM languages happily throw and consume them in the manner of runtime exceptions. It is possible to use some generics gymnastics to get the Java compiler to do this too - the technique is described here.
URunnable
declares a new abstract method for lambdas to implement and it re-throws any exceptions using a default implementation of run
.
@java.lang.FunctionalInterface public interface URunnable extends java.lang.Runnable { default void run() { try { $run(); } catch (Throwable throwable) { uk.kludje.Exceptions.throwChecked(throwable); throw new AssertionError(); //unreachable code } } void $run() throws Throwable; }
No comments:
Post a Comment
All comments are moderated