【问题标题】: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。

标签: java lambda java-8 currying


【解决方案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 编译器,它允许你使用“有效最终”的东西
  • @gstackoverflow 是的,但是 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 设置为参数值。

          【讨论】:

            猜你喜欢
            • 2014-03-16
            • 2013-05-01
            • 1970-01-01
            • 2021-03-28
            • 2021-05-10
            • 2019-10-23
            相关资源
            最近更新 更多