Exception Handling in Java Streams
Tags: java, codequality
Published: 2020-09-11 17:08:40

The Stream API and lambda’s where a big improvement in Java since version 8. From that point on, we could work with a more functional syntax style. Now, after a few years of working with these code constructions, one of the bigger issues that remain is how to deal with checked exceptions inside a lambda.

As you all probably know, it is not possible to call a method that throws a checked exception from a lambda directly. In some way, we need to catch the exception to make the code compile. Naturally, we can do a simple try-catch inside the lambda and wrap the exception into a `RuntimeException`, as shown in the first example, but I think we can all agree that this is not the best way to go.

```java
myList.stream()
  .map(item -> {
    try {
      return doSomething(item);
    } catch (MyException e) {
      throw new RuntimeException(e);
    }
  })
  .forEach(System.out::println);
```

Most of us are aware that block lambdas are clunky and less readable. They should be avoided as much as possible, in my opinion. If we need to do more than a single line, we can extract the function body into a separate method and simply call the new method. A better and more readable way to solve this problem is to wrap the call in a plain old method that does the try-catch and call that method from within your lambda. 

```java
myList.stream()
  .map(this::trySomething)
  .forEach(System.out::println);
private Item trySomething(Item item) {
  try {
    return doSomething(item);
  } catch (MyException e) {
    throw new RuntimeException(e);
  }
}
```

This solution is at least a bit more readable and we do separate our concerns. If you really want to catch the exception and do something specific and not simply wrap the exception into a `RuntimeException`, this can be a possible and readable solution for you.

## RuntimeException

In many cases, you will see that people use these kinds of solutions to repack the exception into a `RuntimeException` or a more specific implementation of an unchecked Exception. By doing so, the method can be called inside a lambda and be used in higher-order functions.

I can relate a bit to this practice because I personally do not see much value in checked exceptions in general, but that is a whole other discussion that I am not going to start here. If you want to wrap every call in a lambda that has a checked into a `RuntimeException`, you will see that you repeat the same pattern. To avoid rewriting the same code over and over again, why not abstract it into a utility function? This way, you only have to write it once and call it every time you need it.

To do so, you first need to write your own version of the functional interface for a function. Only this time, you need to define that the function may throw an exception.

```java
@FunctionalInterface
public interface CheckedFunction<T,R> {
    R apply(T t) throws Exception;
}
```

Now, you are ready to write your own general utility function that accepts a `CheckedFunction` as you just described in the interface. You can handle the try-catch in this utility function and wrap the original exception into a `RuntimeException` (or some other unchecked variant). I know that we now end up with an ugly block lambda here and you could abstract the body from this. Choose for yourself if that is worth the effort for this single utility. 

```java
public static <T,R> Function<T,R> wrap(CheckedFunction<T,R> checkedFunction) {
  return t -> {
    try {
      return checkedFunction.apply(t);
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  };
}
```

With a simple static import, you can now wrap the lambda that may throw an exception with your brand new utility function. From this point on, everything will work again. 

```java
myList.stream()
       .map(wrap(item -> doSomething(item)))
       .forEach(System.out::println);
```


The only problem left is that when an exception occurs, the processing of your stream stops immediately. If that is no problem for you, then go for it. I can imagine, however, that direct termination is not ideal in many situations.

## Either

When working with streams, we probably don't want to stop processing the stream if an exception occurs. If your stream contains a very large amount of items that need to be processed, do you want that stream to terminate when for instance the second item throws an exception? Probably not.

Let's turn our way of thinking around. Why not consider "the exceptional situation" just as much as a possible result as we would for a "successful" result. Let's consider it both as data, continuing to process the stream, and decide afterward what to do with it. We can do that, but to make it possible, we need to introduce a new type — the Either type.

The Either type is a common type in functional languages and not (yet) part of Java. Similar to the Optional type in Java, an `Either` is a generic wrapper with two possibilities. It can either be a Left or a Right but never both. Both left and right can be of any types. For instance, if we have an Either value, this value can either hold something of type String or of type Integer, `Either<String,Integer>`.


If we use this principle for exception handling, we can say that our `Either` type holds either an  Exception or a value. By convenience, normally, the left is the Exception and the right is the successful value. You can remember this by thinking of the right as not only the right-hand side but also as a synonym for “good,” “ok,” etc.

Below, you will see a basic implementation of the `Either` type. In this case, I used the  `Optional` type when we try to get the left or the right because we:

```java
public class Either<L, R> {
    private final L left;
    private final R right;
    private Either(L left, R right) {
        this.left = left;
        this.right = right;
    }
    public static <L,R> Either<L,R> Left( L value) {
        return new Either(value, null);
    }
    public static <L,R> Either<L,R> Right( R value) {
        return new Either(null, value);
    }
    public Optional<L> getLeft() {
        return Optional.ofNullable(left);
    }
    public Optional<R> getRight() {
        return Optional.ofNullable(right);
    }
    public boolean isLeft() {
        return left != null;
    }
    public boolean isRight() {
        return right != null;
    }
    public <T> Optional<T> mapLeft(Function<? super L, T> mapper) {
        if (isLeft()) {
            return Optional.of(mapper.apply(left));
        }
        return Optional.empty();
    }
    public <T> Optional<T> mapRight(Function<? super R, T> mapper) {
        if (isRight()) {
            return Optional.of(mapper.apply(right));
        }
        return Optional.empty();
    }
    public String toString() {
        if (isLeft()) {
            return "Left(" + left +")";
        }
        return "Right(" + right +")";
    }
}
```

You can now make your own functions return an `Either` instead of throwing an `Exception`. But that doesn't help you if you want to use existing methods that throw a checked  Exception inside a lambda right? Therefore, we have to add a tiny utility function to the Either type I described above.

```java
public static <T,R> Function<T, Either> lift(CheckedFunction<T,R> function) {
  return t -> {
    try {
      return Either.Right(function.apply(t));
    } catch (Exception ex) {
      return Either.Left(ex);
    }
  };
}
```

By adding this static lift method to the `Either`, we can now simply "lift" a function that throws a checked exception and let it return an `Either`. If we take the original problem, we now end up with a Stream of Eithers instead of a possible `RuntimeException` that may blow up my entire `Stream`.

```java
myList.stream()
       .map(Either.lift(item -> doSomething(item)))
       .forEach(System.out::println);
```


This simply means that we have taken back control. By using the filter function in the Stream API, we can simply filter out the left instances and, for example, log them. You can also filter the right instances and simply ignore the exceptional cases. Either way, you are back in control again and your stream will not terminate instantly when a possible `RuntimeException` occurs.

Because `Either` is a generic wrapper, it can be used for any type, not just for exception handling. This gives us the opportunity to do more than just wrapping the `Exception` into the left part of an `Either`. The issue we now might have is that if the `Either` only holds the wrapped exception, and we cannot do a retry because we lost the original value. By using the ability of the `Either` to hold anything, we can store both the exception and the value inside a left. To do so, we simply make a second static lift function like this.

```java
public static <T,R> Function<T, Either> liftWithValue(CheckedFunction<T,R> function) {
  return t -> {
    try {
      return Either.Right(function.apply(t));
    } catch (Exception ex) {
      return Either.Left(Pair.of(ex,t));
    }
  };
}
```

You see that in this `liftWithValue` function within the `Pair` type is used to pair both the exception and the original value into the left of an `Either`.  Now, we have all the information we possibly need if something goes wrong, instead of only having the `Exception`. 

The `Pair` type used here is another generic type that can be found in the Eclipse Collections library, or you can simply implement your own. Anyway, it is just a type that can hold two values.

```java
public class Pair<F,S> {
    public final F fst;
    public final S snd;
    private Pair(F fst, S snd) {
        this.fst = fst;
        this.snd = snd;
    }
    public static <F,S> Pair<F,S> of(F fst, S snd) {
        return new Pair<>(fst,snd);
    }
}
```

With the use of the `liftWithValue`, you now have all the flexibility and control to use methods that may throw an `Exception` inside a lambda. When the `Either` is a right, we know that the function was applied correctly and we can extract the result. If, on the other hand, the `Either` is a left, we know something went wrong and we can extract both the `Exception` and the original value, so we can proceed as we like. By using the `Either` type instead of wrapping the checked  `Exception` into a `RuntimeException`, we prevent the `Stream` from terminating halfway.

## Try
People that may have worked with for instance Scala may use the `Try` instead of the `Either` for exception handling. The `Try` type is something that is very similar to the  `Either` type. It has, again, two cases: “success” or “failure.” The failure can only hold the type Exception, while the success can hold anything type you want. So, the `Try` is nothing more than a specific implementation of the `Either` where the left type (the failure) is fixed to type `Exception`.

```java
public class Try<Exception, R> {
    private final Exception failure;
    private final R succes;
    public Try(Exception failure, R succes) {
        this.failure = failure;
        this.succes = succes;
    }
}
```


Some people are convinced that it is easier to use, but I think that because we can only hold the `Exception `itself in the failure part, we have the same problem as explained in the first part of the `Either` section. I personally like the flexibility of the `Either` type more. Anyway, in both cases, if you use the `Try` or the `Either`, you solve the initial problem of exception handling and do not let your stream terminate because of a RuntimeException.

## Libraries
Both the `Either` and the `Try` are very easy to implement yourself. On the other hand, you can also take a look at functional libraries that are available. For instance, VAVR (formerly known as Javaslang) does have implementations for both types and helper functions available. I do advise you to take a look at it because it holds a lot more than only these two types. However, you have ask yourself the question of whether you want this large library as a dependency just for exception handling when you can implement it yourself with just a few lines of code.

## Conclusion
When you want to use a method that throws a  `checkedException`, you have to do something extra if you want to call it in a lambda. Wrapping it into a `RuntimeException` can be a solution to make it work. If you prefer to use this method, I urge you to create a simple wrapper tool and reuse it, so you are not bothered by the `try/catch` every time. 

If you want to have more control, you can use the `Either` or `Try` types to wrap the outcome of the function, so you can handle it as a piece of data. The stream will not terminate when a `RuntimeException` is thrown and you have the liberty to handle the data inside your stream as you please.