Java 8 中带有 2 个箭头的 lambda 是啥意思?

Posted

技术标签:

【中文标题】Java 8 中带有 2 个箭头的 lambda 是啥意思?【英文标题】:What does lambda with 2 arrows mean in Java 8?Java 8 中带有 2 个箭头的 lambda 是什么意思? 【发布时间】:2015-12-25 13:28:10 【问题描述】:

我之前读过几篇 Java 8 教程。

现在我遇到了以下话题: Does java support Currying?

在这里,我看到以下代码:

IntFunction<IntUnaryOperator> curriedAdd = a -> b -> a + b;
System.out.println(curriedAdd.apply(1).applyAsInt(12));

我知道这个示例包含 2 个元素,但我无法理解结构:

a -> b -> a + b;

根据表达式的左边部分,该行应实现以下功能:

R apply(int value); 

在此之前,我只遇到过只有一个箭头的 lambdas。

【问题讨论】:

你明白柯里化是什么意思吗?这对这个问题非常重要。 只是一个返回 lambda 的 lambda。 【参考方案1】:

如果您将其表达为非速记 lambda 语法或 pre-lambda Java 匿名类语法,那么发生了什么会更清楚......

原来的问题。为什么是两个箭头?很简单,定义了两个函数……第一个函数是函数定义函数,第二个是该函数的结果,也恰好是函数。每个都需要一个-&gt; 运算符来定义它。

非速记

IntFunction<IntUnaryOperator> curriedAdd = (a) -> 
    return (b) -> 
        return a + b;
    ;
;

Java 8 之前的 Pre-Lambda

IntFunction<IntUnaryOperator> curriedAdd = new IntFunction<IntUnaryOperator>() 
    @Override
    public IntUnaryOperator apply(final int value) 
        IntUnaryOperator op = new IntUnaryOperator() 
            @Override
            public int applyAsInt(int operand) 
                return operand + value;
            
        ;
        return op;
    
;

【讨论】:

pre-lambda 需要 final int value 是的,你是对的,但我写的仍然是使用 Java 8 编译器,它允许你使用“有效最终”的东西 @g*** 是的,但是 java 8 不是 pre-lambda 你也可以在 java 8 中使用 pre-lambda 样式。我写的 JFY 不是 lambdas 只是为了让人们得分吗? :-)【参考方案2】:

IntFunction&lt;R&gt; 是一个函数 int -&gt; RIntUnaryOperator 是一个函数 int -&gt; int

因此IntFunction&lt;IntUnaryOperator&gt; 是一个以int 作为参数并返回以int 作为参数并返回int 的函数的函数。

a -> b -> a + b;
^    |         |
|     ---------
|         ^
|         |
|         The IntUnaryOperator (that takes an int, b) and return an int (the sum of a and b)
|
The parameter you give to the IntFunction

如果您使用匿名类来“分解” lambda,也许会更清楚:

IntFunction<IntUnaryOperator> add = new IntFunction<IntUnaryOperator>() 
    @Override
    public IntUnaryOperator apply(int a) 
        return new IntUnaryOperator() 
            @Override
            public int applyAsInt(int b) 
                return a + b;
            
        ;
    
;

【讨论】:

【参考方案3】:

添加括号可能会更清楚:

IntFunction<IntUnaryOperator> curriedAdd = a -> (b -> (a + b));

或者中间变量可能会有所帮助:

IntFunction<IntUnaryOperator> curriedAdd = a -> 
    IntUnaryOperator op = b -> a + b;
    return op;
;

【讨论】:

【参考方案4】:

让我们用括号重写那个 lambda 表达式以使其更清楚:

IntFunction<IntUnaryOperator> curriedAdd = a -> (b -> (a + b));

所以我们声明了一个函数,它接受一个int,它返回一个Function。更具体地说,返回的函数接受 int 并返回 int(两个元素的总和):这可以表示为 IntUnaryOperator

因此,curriedAdd 是一个接受int 并返回IntUnaryOperator 的函数,因此它可以表示为IntFunction&lt;IntUnaryOperator&gt;

【讨论】:

【参考方案5】:

这是两个 lambda 表达式。

IntFunction<IntUnaryOperator> curriedAdd = 
  a ->  //this is for the fixed value
    return b ->  //this is for the add operation
      return a + b;
    ;
  

IntUnaryOperator addTwo = curriedAdd.apply(2);
System.out.println(addTwo.applyAsInt(12)); //prints 14

【讨论】:

【参考方案6】:

如果您查看IntFunction,它可能会变得更清楚:IntFunction&lt;R&gt;FunctionalInterface。它表示一个接受int 并返回R 类型值的函数。

在这种情况下,返回类型R也是FunctionalInterface,即IntUnaryOperator。所以 first(外部)函数本身返回一个函数。

在这种情况下:当应用于 int 时,curriedAdd 应该返回一个再次采用 int 的函数(并再次返回 int,因为这是 IntUnaryOperator 所做的)。

在函数式编程中,将函数的类型写成param -&gt; return_value 是很常见的,你在这里可以看到。所以curriedAdd 的类型是int -&gt; int -&gt; int(或者int -&gt; (int -&gt; int),如果你更喜欢的话)。

Java 8 的 lambda 语法也随之而来。要定义这样一个函数,你写

a -> b -> a + b

这与实际的 lambda 演算非常相似:

λa λb a + b

λb a + b 是一个函数,它接受单个参数 b 并返回一个值(总和)。 λa λb a + b 是一个接受单个参数a 并返回单个参数的另一个函数的函数。 λa λb a + b 返回 λb a + b 并将 a 设置为参数值。

【讨论】:

以上是关于Java 8 中带有 2 个箭头的 lambda 是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章

Java Lambda表达式的箭头理解总结

Java Lambda表达式的箭头理解总结

jdk1.8新特性

Android的java代码(下边红波浪线)中带的箭头(“->”)怎么取消

java8新特性-lambda

java8新特性-lambda