If a method which is used within a Java 8 stream processing throws a checked exception, this exception has to be handled. One way to do this is to wrap the checked exception with a java.lang.RuntimeException
and throw it. This results in a extended stacktrace.
This is just a proof of concept inspired by the org.apache.commons.lang3.exception.ExceptionUtils.rethrow(Throwable)
method.
The org.apache.commons.lang3.exception.ExceptionUtils.rethrow(Throwable)
method has an interesting functionality:
Throw a checked exception without adding the exception to the throws clause of the calling method. This method prevents throws clause pollution and reduces the clutter of “Caused by” exceptions in the stacktrace.
…
(see https://commons.apache.org/proper/commons-lang/javadocs/api-release/org/apache/commons/lang3/exception/ExceptionUtils.html#rethrow-java.lang.Throwable-)
First define a functional interface similar to java.util.function.Function<T, R>
which throws a checked exception:
@FunctionalInterface
interface FunctionWithCheckeException<T, R> {
R apply(T t) throws Exception;
}
Then we define a small helper method which “transforms” the FunctionWithCheckeException
to a Function
. This method catches also the checked exceptions and rethrows them:
static <T, R> Function<T, R> toUnchecked(FunctionWithCheckeException<T, R> f) {
return t -> {
try {
return f.apply(t);
} catch (Exception e) {
throwWithTypeErasure(e); // propagates a checked exception
throw new IllegalStateException(); // needed for compiler
}
};
}
private static <T extends Throwable> void throwWithTypeErasure(Throwable throwable) throws T {
throw (T) throwable;
}
The throwWithTypeErasure
method is similar to org.apache.commons.lang3.exception.ExceptionUtils.rethrow(Throwable)
.
public static void main(String[] args) {
Stream.of("1", "2", "3")
.map(toUnchecked(Test::functionWithChecked))
.forEach(System.out::println);
}
int functionWithChecked(String s) throws ClassNotFoundException {
throw new ClassNotFoundException();
}
This prints the stacktrace;
Exception in thread "main" java.lang.ClassNotFoundException
at Test.functionWithChecked(Test.java:44)
at Test.lambda$0(Test.java:54)
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193)
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:948)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at Test.main(Test.java:15)
Note that there is the original exception on the top of the stacktrace.