Handling Exceptions in Java Streams using a Functional Interface
Tags: java, functional, refacorit
Published: 2021-08-20 01:08:40

I was reviewing some code recently and ran into something like this: 
```Java
subject.getIdentities().forEach(i -> {
  try {
    caseService.updateDocument(i.getCase());
  } catch (Exception e) {
    log.error(e); 
  }
});
```
If you have read my other articles about functional programming concepts in Java ([here](https://dev.to/phouchens/exploring-functional-programming-in-java-functional-interfaces-1phe) and [here](https://dev.to/phouchens/functional-programming-in-java-refactoring-if-else-logic-with-the-help-of-functional-interfaces-2hcj)), you can probably guess that I am a big fan of lambda expressions. However, one of the primary advantages of using lambda expressions is terseness. The above code looks not-so-terse and a bit messy to me. How can we clean this up? Functional interfaces to the rescue. 

What do we need? We know that a [forEach](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#forEach-java.util.function.Consumer-) expects a Consumer as an input. If we could wrap our logic that handles an exception in a Consumer, we could use the logic in the forEach. 

The main logic inside the forEach is the following line:
```Java
//try catch removed
// i is an Identity and updateDocument returns a UpdateResponse
i -> caseService.updateDocument(i.getCase());
```
We know the input and the return type, and we can create a functional interface whose method throws an Exception.
```Java
@FunctionalInterface
public interface ThrowingFunction<Identity, UpdateResponse> {
  UpdateResponse apply(Identity i) throws Exception;
}
```
We can make this more usable with generics.
```Java
@FunctionalInterface
public interface ThrowingFunction<T, R> {
  R apply(T t) throws Exception;
}
```
With the interface created, the original logic can be target typed as such: 
```Java
ThrowingFunction<Identity, UpdateResponse> tf = i -> caseService.updateDocument(i.getCase());
```
Now that we have a functional interface for our logic, we can pass it as a parameter to a method that handles the exception and returns a Consumer we can use in the forEach.
```Java
private static <T, R> Consumer<T> wrap(ThrowingFunction<T, R> f) {
  return t -> {
    try  {
      f.apply(t);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  };
}

```
It's a little weird looking, but essentially the wrap method takes a ThrowingFunction as input and handles executing the function or catching and throwing the Exception in a Consumer.

Now we can wrap any logic used inside a forEach that may throw an exception. It looks something like this:

```Java
// target type the original logic
ThrowingFunction<Identity, UpdateResponse> tf = i -> caseService.updateDocument(i.getCase()):

// pass logic to the wrapmethod
// which will execute the function or throw a RunTimeException. 
Consumer<Identity> p = wrap(tf);

// use Consumer in foreach
subject.getIdentities().forEach(p); 

```
Or if you prefer one line:
```Java
subject.getIdentities().forEach(wrap(i -> caseService.updateDocument(i.getCase())));
```
Much better! You could implement something similar to handle different types of functional interfaces. For instance, a [map](https://docs.oracle.com/javase/8/docs/api/java/util/stream/Stream.html#map-java.util.function.Function-) operation only takes a [Function](https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html) as an input. Instead of a wrap method that returns a Consumer you could have a method that returns a Function. 
This is just one pattern for handling exceptions in streams. I should mention there are [libraries](https://www.jooq.org/products/jOO%CE%BB/javadoc/0.9.5/org/jooq/lambda/Unchecked.html) that do this kind of thing for you if you don't want to roll with your own implementation. Or you could use a monad to handle success/failures, but that is beyond the scope of this post. Let me know if you have implemented any other ways of handling exceptions in streams!