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

最后修改: 2017年 6月 27日

中文/混合/英文(键盘快捷键:t)

1. Introduction

1.介绍

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.

JDK所提供的功能接口没有为处理检查过的异常做好准备。如果你想了解更多关于这个问题的信息,请查看这篇文章。

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

在本文中,我们将探讨使用功能型Java库Vavr来克服此类问题的各种方法。

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

要获得有关Vavr以及如何设置它的更多信息,请查看这篇文章

2. Using CheckedFunction

2.使用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:

我们可以在lambda表达式里面使用上述方法,而不用处理IOException

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

CheckedFunction1<Integer, Integer> readFunction = i -> readFromFile(i);
integers.stream()
 .map(readFunction.unchecked());

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

正如你所看到的,没有标准的try-catch或包装方法,我们仍然可以在lambda表达式中调用抛出异常的方法。

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

3.使用帮助者方法

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

API类为上一节中的例子提供了一个快捷的方法。

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

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

4. Using Lifting

4.使用举动

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.

为了优雅地处理IOException,我们可以在lambda表达式中引入标准的try-catch块。然而,lambda表达式的简洁性将会丧失。Vavr的提升功能来拯救我们。

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

提升是函数式编程的一个概念。你可以将一个部分函数提升到一个总函数,该函数返回一个Option作为结果。

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);
 
integers.stream()
  .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.

请注意,解除函数的结果是Option,如果出现异常,结果将是Option.None。方法getOrElse()Option.None的情况下需要返回一个备用的值。

5. Using Try

5.使用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.

虽然上一节中的方法lift()解决了程序突然终止的问题,但它实际上吞噬了这个异常。因此,我们方法的消费者不知道是什么导致了默认值。替代方法是使用Try容器。

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.

Try是一个特殊的容器,我们可以用它来封装一个可能会抛出异常的操作。在这种情况下,产生的Try对象代表一个Failure,它包裹着异常。

Let’s look at the code that uses Try:

让我们看一下使用Try的代码。

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

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

要了解有关Try容器的更多信息以及如何使用它,请查看这篇文章

6. Conclusion

6.结论

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.

在这篇快速文章中,我们展示了如何使用Vavr库的功能来规避问题,同时处理lambda表达式中的异常。

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.

本文中所有例子的完整源代码可以在Github上找到over