Exceptions in Lambda Expression Using Vavr – 使用Vavr的Lambda表达式的异常情况

最后修改: 2017年 6月 27日

1. Introduction


The Functional Interfaces provided by the JDK are not prepared properly for the handling of checked exceptions. If you want to read more about the problem, check this article.


In this article, we’ll look at various ways to overcome such problems using the functional Java library Vavr.


To get more information about Vavr and how to set it up, check out this article.


2. Using CheckedFunction


Vavr provides functional Interfaces that have functions that throw checked exceptions. These functions are CheckedFunction0, CheckedFunction1 and so on till CheckedFunction8. The 0, 1, … 8 at the end of the function name indicates the number of input arguments for the function.

Vavr提供了功能接口,这些接口有抛出检查异常的函数。这些函数是CheckedFunction0CheckedFunction1,以此类推,直到CheckedFunction8。函数名称后面的0, 1, … 8表示该函数的输入参数数。

Let’s see an example:


static Integer readFromFile(Integer integer) throws IOException {
    // logic to read from file which throws IOException

We can use the above method inside a lambda expression without handling the IOException:


List<Integer> integers = Arrays.asList(3, 9, 7, 0, 10, 20);

CheckedFunction1<Integer, Integer> readFunction = i -> readFromFile(i);

As you can see, without the standard try-catch or the wrapper methods, we can still call exception throwing methods inside a lambda expression.


We must exercise caution while using this feature with the Stream API, as an exception would immediately terminate the operation – abandoning the rest of the stream.

在使用Stream API时,我们必须谨慎行事,因为一个异常将立即终止操作–放弃流的其余部分。

3. Using Helper Methods


The API class provides a shortcut method for the example in the previous section:


List<Integer> integers = Arrays.asList(3, 9, 7, 0, 10, 20);

  .map(API.unchecked(i -> readFromFile(i)));

4. Using Lifting


To handle an IOException gracefully, we can introduce standard try-catch blocks inside a lambda expression. However, the conciseness of a lambda expression will be lost. Vavr’s lifting comes to our rescue.


Lifting is a concept from functional programming. You can lift a partial function to a total function that returns an Option as result.


A partial function is a function that is defined only for a subset of a domain as opposed to a total function which is defined for the entirety of its domain. If the partial function is called with input that is outside of its supporting range, it will typically throw an exception.


Let’s rewrite the example from the previous section:


List<Integer> integers = Arrays.asList(3, 9, 7, 0, 10, 20);
  .map(CheckedFunction1.lift(i -> readFromFile(i)))
  .map(k -> k.getOrElse(-1));

Note that the result of the lifted function is Option and the result will be Option.None in case of an exception. The method getOrElse() takes an alternate value to return in case of Option.None.


5. Using Try


While the method lift() in the previous section solves the issue of abrupt program termination, it actually swallows the exception. Consequently, the consumer of our method has no idea on what resulted in the default value. The alternative is to use a Try container.


Try is a special container with which we can enclose an operation that might possibly throw an exception. In this case, the resulting Try object represents a Failure and it wraps the exception.


Let’s look at the code that uses Try:


List<Integer> integers = Arrays.asList(3, 9, 7, 0, 10, 20);
  .map(CheckedFunction1.liftTry(i -> readFromFile(i)))
  .forEach(i -> processValidValue(i));

To learn more on the Try container and how to use it, check this article.


6. Conclusion


In this quick article, we showed how to use the features from the Vavr library to circumvent the problems while dealing with exceptions in lambda expressions.


Although these features allow us to elegantly deal with exceptions, they should be used with utmost care. With some of these approaches, consumers of your methods may be surprised with unexpected checked exceptions, although they are not explicitly declared.


The complete source code for all the examples in this article can be found over on Github.