When you've got a java.lang.Runnable
that can throw checked exceptions, you have to handle them all explicitly since the Runnable
interface doesn't have a throws
clause. The same is true for other functional interfaces like Consumer
, Supplier
in java.util.function
.
This little library gives you a twin interface for each of those. But the twin is declared with a throws Throwable
clause. Through trickery stolen borrowed from vavr these functional interfaces can be used where the JDK ones are expected.
Example:
public class ExampleTest {
// a checked exception
static class Bad extends Exception {
}
// a method that needs a Runnable. Runnables can't throw checked exceptions
private static void invokeRunnable(final Runnable runnable) {
runnable.run();
}
@Test
public void compilesAndThrows() {
final boolean state = true;
assertThatThrownBy(
() ->
invokeRunnable(
() -> {
if (state) {
throw new Bad();
} else {
System.out.println("Ran!");
}
})).isInstanceOf(Bad.class);
}
}
In the example invokeRunnable()
wants a Runnable
. But this won't compile because the lambda we are passing throws a checked exception.
We could try this instead:
public class ExampleTest {
@Test
public void compilesAndThrows() {
final boolean state = true;
assertThatThrownBy(
() ->
invokeRunnable(
() -> {
if (state) {
try {
throw new Bad();
} catch (Bad bad) {
// !! NOW WHAT?!?
}
} else {
System.out.println("Ran!");
}
})).isInstanceOf(Bad.class);
}
}
While this compiles, it leaves us wondering what to do in the catch
block?
CheckedRunnable
disguises a checked-exception-throwing lambda as a Runnable
like this:
public class ExampleTest {
@Test
public void compilesAndThrows() {
final boolean state = true;
assertThatThrownBy(
() ->
invokeRunnable(
CheckedRunnable.of(() -> {
if (state) {
throw new Bad();
} else {
System.out.println("Ran!");
}
}).unchecked())).isInstanceOf(Bad.class);
}
}
We used CheckedRunnable.of()
to construct a CheckedRunnable
from our lambda and then we used unchecked()
to convert that into a Runnable
. As you can see, not only does this compile, but also the checked exception propagates at runtime.