BiFunction接口中的默认andThen()方法

6

BiFunction 接口 (java.util.function 包) 中有一个默认方法 andThen()

default <V> BiFunction<T,U,V> andThen(Function<? super R,? extends V> after)

文档说明如下:

返回一个组合函数,首先将此函数应用于其输入,然后将结果应用于 after 函数。如果任一函数的评估引发异常,则将其中继到组合函数的调用者。

理解这个解释有点困难。据我理解,当调用默认的 andThen() 方法时,会返回一个组合函数。该组合函数在类型 TU 上被调用,返回类型为 V。最后,在类型 RV 上调用 after 函数。

这个方法的需要是什么?它实际上如何适合这个情况?

4个回答

5
理解这个解释可能有些困惑。
简单地说,方法andThen返回一个函数,该函数首先将给定的函数应用于输入,然后将另一个函数应用于该应用结果。
假设我们有两个函数fg,函数f执行一些逻辑,函数g执行其他类型的逻辑,因此当您组合f.andThen(g)时,这实际上意味着g(f(x)),即我们首先应用作为参数的函数f(x),然后将函数g应用于结果。
示例:
BiFunction<Integer, Integer, Integer> f = Math::addExact; 
Function<Integer, Integer> g = e -> e * 2; 
System.out.println(f.andThen(g).apply(10,10)); // 40

我们首先调用函数f(10, 10),然后取得结果20,将其传递给函数g(20)执行,乘以2后得到40
说实话,在Java中调用函数的语法并不是最好的,我可以理解第一次看到这个可能很难理解,并且随着您组合更多函数,它变得越来越难以跟踪。例如,在C#中,您可以简单地执行g(f(10, 10)),这在视觉上更容易跟踪、阅读和理解。
“这种方法有什么必要?它如何真正适应整个过程?”
根据我的经验,我很少像上面展示的那样组合函数,但我可以想象一个典型的场景是,如果您有各种实用程序方法来执行某些逻辑操作,其中一个函数的结果会进一步传递给其他函数进行处理,那么您就可以使用函数组合来创建各种转换管道,通过组合实用程序方法来完成。

通过柯里化实现类型安全的构建器 - Eugene
怎么回事?我这里没听懂你的意思。 - Eugene
@Eugene 我的意思是涉及Java-8、java-stream的问题。 - Ousmane D.
哦,我猜我现在才开始看它... :) - Eugene

2

考虑 f1.andThen(f2)

  1. 首先,f1 会取两个元素并产生仅为一个结果
  2. 然后,f2 将取得 f1 的结果并将其转换为另一个结果
BiFunction<Integer, Integer, Integer> plus10 = (i1, i2) -> i1 + i2 + 10;

Function<Integer, Integer> mult = i -> i * 5;

System.out.println(plus10.andThen(mult).apply(5, 6)); // (5+6+10) *5 = 105

这是一种减少计算量的方法

int val1 = plus10.apply(5, 6);
int res1 = mult.apply(val1);

int res2 = plus10.andThen(mult).apply(5, 6);
System.out.println(res1 == res2);            //true

当你有多个需要使用的函数时,使用同一个方法Function进行链接变得越来越有用:

System.out.println(plus10.andThen(mult).andThen(mult).andThen(mult).apply(5, 6)); 
// (5+6+10)*5*5*5 = 2625

2
我认为andThen函数的主要目的是使您的代码更易读、更加功能化。
让我们看一个例子:
BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y;
Function<Integer, Integer> negate = x -> -x;
BiFunction<Integer, Integer, Integer> newFunction = add.andThen(negate);

猜猜newFunction是做什么的?它将两个数字相加,然后取反!看看这一行和英语有多相似:

BiFunction<Integer, Integer, Integer> newFunction = add.andThen(negate);

如果您调用.apply(1, 2),那么您知道您将得到-3。
当然,您可以不使用andThen来完成这个操作:
BiFunction<Integer, Integer, Integer> newFunction = (x, y) -> negate.apply(add.apply(x, y))

但看看这是多么难以阅读!

函数式编程有时可以使事情更易于阅读和理解。


0

举个例子更容易理解:

BiFunction<Integer, Integer, String> f = 
        (n1, n2) -> String.format("result is %s", n1+n2);

而“组合函数”是:

BiFunction<Integer, Integer, String> f1 = 
        f.andThen(string -> string.toUpperCase());

请注意,第二个函数仍然使用与第一个函数相同的参数类型,尽管它在内部只需要一个字符串来执行其逻辑。
考虑调用:
System.out.println(f1.apply(2, 3));

这将输出RESULT IS 5,即:它先调用第一个函数,然后使用第一个函数的结果调用第二个函数。因此,它可以简单地理解为f1(f(x, y)),其中最终输入是f所需的输入,最终结果是f1产生的结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接