Class LambdaExceptionUtils
- java.lang.Object
-
- org.forgerock.util.LambdaExceptionUtils
-
public final class LambdaExceptionUtils extends Object
Utility methods for interacting with lambdas that throw exceptions.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 theClassNotFoundException
gets caught and logged, and thatclasses
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 theStream.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 thecollect
call, and results in thegetClasses()
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.
- See Also:
- The source on Stack Overflow
-
-
Method Summary
All Methods Static Methods Concrete Methods Modifier and Type Method Description static <T,U,R,E extends Exception>
BiFunction<T,U,R>rethrowBiFunction(BiFunction<T,U,R,E> function)
Wrap aBiFunction
to comply withBiFunction
's no checked exception signature.static <T,E extends Exception>
Consumer<T>rethrowConsumer(Consumer<T,E> consumer)
static <T,R,E extends Exception>
Function<T,R>rethrowFunction(Function<T,R,E> function)
static <T,E extends Exception>
Predicate<T>rethrowPredicate(Predicate<T,E> predicate)
static <T,E extends Exception>
Supplier<T>rethrowSupplier(Supplier<T,E> supplier)
-
-
-
Method Detail
-
rethrowConsumer
public static <T,E extends Exception> Consumer<T> rethrowConsumer(Consumer<T,E> consumer) throws E extends Exception
Wrap aConsumer
to comply withConsumer
'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.
- Type Parameters:
T
- The type of the consumed object.E
- The type of exception thrown.- Parameters:
consumer
- TheConsumer
that throws the checked exception- Returns:
- A
Consumer
that appears not to the throw the checked exception. - Throws:
E
- This method does not really throwE
- the compiler is tricked into thinking it does.E extends Exception
-
rethrowPredicate
public static <T,E extends Exception> Predicate<T> rethrowPredicate(Predicate<T,E> predicate) throws E extends Exception
Wrap aPredicate
to comply withPredicate
'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.
- Type Parameters:
T
- The type of the predicate test object.E
- The type of exception thrown.- Parameters:
predicate
- ThePredicate
that throws the checked exception- Returns:
- A
Predicate
that appears not to the throw the checked exception. - Throws:
E
- This method does not really throwE
- the compiler is tricked into thinking it does.E extends Exception
-
rethrowSupplier
public static <T,E extends Exception> Supplier<T> rethrowSupplier(Supplier<T,E> supplier) throws E extends Exception
Wrap aSupplier
to comply withSupplier
'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.
- Type Parameters:
T
- The type of the supplied object.E
- The type of exception thrown.- Parameters:
supplier
- TheSupplier
that throws the checked exception- Returns:
- A
Supplier
that appears not to the throw the checked exception. - Throws:
E
- This method does not really throwE
- the compiler is tricked into thinking it does.E extends Exception
-
rethrowFunction
public static <T,R,E extends Exception> Function<T,R> rethrowFunction(Function<T,R,E> function) throws E extends Exception
Wrap a throwingFunction
to comply withFunction
'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.
- Type Parameters:
T
- The type of the consumed object.R
- The type of the result.E
- The type of exception thrown.- Parameters:
function
- TheFunction
that throws the checked exception- Returns:
- A
Function
that appears not to the throw the checked exception. - Throws:
E
- This method does not really throwE
- the compiler is tricked into thinking it does.E extends Exception
-
rethrowBiFunction
public static <T,U,R,E extends Exception> BiFunction<T,U,R> rethrowBiFunction(BiFunction<T,U,R,E> function) throws E extends Exception
Wrap aBiFunction
to comply withBiFunction
'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.
- Type Parameters:
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.- Parameters:
function
- TheBiFunction
that throws the checked exception- Returns:
- A
BiFunction
that appears not to the throw the checked exception. - Throws:
E
- This method does not really throwE
- the compiler is tricked into thinking it does.E extends Exception
-
-