public final class LambdaExceptionUtils extends Object
WARNING: The methods provided here give a way to make the compiler believe that the exception that is
being thrown from the lambda expression is thrown out of the rethrowXxx
method, rather than from
wherever the consumer of the lambda actually invokes the lambda. These methods do not change where
exceptions actually come from!
Provided you use this only when your use of lambdas is completely contained within an exception handling block, then this is perfectly safe to do, but you need to consider carefully what the usage of your lambda is going to be. Consider the following example:
public List<Class<?>> getClasses() {
List<Stream> classNames = Arrays.asList("my.Class");
Stream<Class<?>> classes;
try {
classes = classNames.stream().map(rethrowFunction(Class::forName));
} catch (ClassNotFoundException e) {
log.debug("Class not found", e);
classes = Stream.empty();
}
return classes.collect(Collectors.toList());
}
What happens when my.Class
does not exist? It would appear from this code that the answer is that the
ClassNotFoundException
gets caught and logged, and that classes
gets initialised to an empty
stream that will then be collected to a list, which will also be empty.
However, you need to remember how the Stream
uses the lambda passed in the
Stream.map(java.util.function.Function)
method - streams only actually evaluate the
lambdas from map and filter type operations at the point at which the stream is actually terminated -
when you call a method that produces a result or a side-effect - in this case,
Stream.collect(java.util.stream.Collector)
.
So what actually happens in the above example is that the ClassNotFoundException
actually gets thrown
from the collect
call, and results in the getClasses()
method actually throwing a checked
exception that it hasn't declared. Also, the exception is not in fact ever logged because that catch block will
never be invoked (nothing in the try actually throws an exception).
The correct way of making use of the rethrowFunction
method in this example would be as follows:
public List<Class<?>> getClasses() {
List<Stream> classNames = Arrays.asList("my.Class");
try {
return classNames.stream().map(rethrowFunction(Class::forName)).collect(Collectors.toList());
} catch (ClassNotFoundException e) {
log.debug("Class not found", e);
return Collections.emptyList();
}
}
Here the use of the lambda is contained within the same exception handling block.
Modifier and Type | Method and Description |
---|---|
static <T,U,R,E extends Exception> |
rethrowBiFunction(BiFunction<T,U,R,E> function)
Wrap a
BiFunction to comply with BiFunction 's no checked
exception signature. |
static <T,E extends Exception> |
rethrowConsumer(Consumer<T,E> consumer)
|
static <T,R,E extends Exception> |
rethrowFunction(Function<T,R,E> function)
|
static <T,E extends Exception> |
rethrowPredicate(Predicate<T,E> predicate)
|
static <T,E extends Exception> |
rethrowSupplier(Supplier<T,E> supplier)
|
public static <T,E extends Exception> Consumer<T> rethrowConsumer(Consumer<T,E> consumer) throws E extends Exception
Consumer
to comply with Consumer
's no checked exception
signature. The underlying exception will actually be thrown and must be handled by the client code.
.forEach(rethrowConsumer(name -> System.out.println(Class.forName(name))))
WARNING: See the class-level javadoc for safety considerations governing use of this method.
T
- The type of the consumed object.E
- The type of exception thrown.consumer
- The Consumer
that throws the checked exceptionConsumer
that appears not to the throw the checked exception.E
- This method does not really throw E
- the compiler is tricked into thinking it does.E extends Exception
public static <T,E extends Exception> Predicate<T> rethrowPredicate(Predicate<T,E> predicate) throws E extends Exception
Predicate
to comply with Predicate
's no checked exception
signature. The underlying exception will actually be thrown and must be handled by the client code.
.filter((t) -> Class.forName("com.acme.MyClass").isAssignableFrom(t.getClass()))
WARNING: See the class-level javadoc for safety considerations governing use of this method.
T
- The type of the predicate test object.E
- The type of exception thrown.predicate
- The Predicate
that throws the checked exceptionPredicate
that appears not to the throw the checked exception.E
- This method does not really throw E
- the compiler is tricked into thinking it does.E extends Exception
public static <T,E extends Exception> Supplier<T> rethrowSupplier(Supplier<T,E> supplier) throws E extends Exception
Supplier
to comply with Supplier
's no checked exception
signature. The underlying exception will actually be thrown and must be handled by the client code.
.orElseGet(() -> Class.forName("com.acme.MyClass"))
WARNING: See the class-level javadoc for safety considerations governing use of this method.
T
- The type of the supplied object.E
- The type of exception thrown.supplier
- The Supplier
that throws the checked exceptionSupplier
that appears not to the throw the checked exception.E
- This method does not really throw E
- the compiler is tricked into thinking it does.E extends Exception
public static <T,R,E extends Exception> Function<T,R> rethrowFunction(Function<T,R,E> function) throws E extends Exception
Function
to comply with Function
's no
checked exception signature. The underlying exception will actually be thrown and must be handled by the
client code.
.map(name -> Class.forName(name))
or .map(Class::forName)
WARNING: See the class-level javadoc for safety considerations governing use of this method.
T
- The type of the consumed object.R
- The type of the result.E
- The type of exception thrown.function
- The Function
that throws the checked exceptionFunction
that appears not to the throw the checked exception.E
- This method does not really throw E
- the compiler is tricked into thinking it does.E extends Exception
public static <T,U,R,E extends Exception> BiFunction<T,U,R> rethrowBiFunction(BiFunction<T,U,R,E> function) throws E extends Exception
BiFunction
to comply with BiFunction
's no checked
exception signature. The underlying exception will actually be thrown and must be handled by the client
code.
WARNING: See the class-level javadoc for safety considerations governing use of this method.
T
- The type of the first consumed object.U
- The type of the second consumed object.R
- The type of the result.E
- The type of exception thrown.function
- The BiFunction
that throws the checked exceptionBiFunction
that appears not to the throw the checked exception.E
- This method does not really throw E
- the compiler is tricked into thinking it does.E extends Exception
Copyright 2010-2022 ForgeRock AS.