Java 8 - 匿名类和lambda函数之间明显不一致

问题描述 投票:1回答:2

在研究Java 8函数式编程时,我发现了以下明显的不一致性。下面的两个结构应该是等价的:

  public static BiFunction<Integer, Integer, Integer> addTwoIntegers (Integer i1, Integer i2)
  {
    return new BiFunction<Integer, Integer, Integer>()
    {
      @Override
      public Integer apply(Integer i1, Integer i2)
      {
        return i1 +i2;
      }
    };
  }

  public static BiFunction<Integer, Integer, Integer> addTwoIntegers2 (Integer i1, Integer i2)
  {
    return (i1x, i2x) -> i1 + i2;
  }

第一个声明是传统的匿名类,而第二个声明是lambda函数,但是它们应该是等价的。现在,按如下方式调用它们:

    System.out.println("addTwoIntegers: " + addTwoIntegers(new Integer(0), new Integer(0)).apply(new Integer(5), new Integer(7)));
    System.out.println("addTwoIntegers2: " + addTwoIntegers2(new Integer(0), new Integer(0)).apply(new Integer(5), new Integer(7)));

我明白了:

addTwoIntegers: 12
addTwoIntegers2: 0

因此,要么两个声明不等同,要么难以承认,或者,如果它们是等价的,假定它们在相同的上下文中具有相同的参数,则它们应该产生相同的结果。这不是一个不一致吗? 非常感谢能在这里遮挡一些光线的人。 亲切的问候,尼古拉斯

java lambda java-8 anonymous-class functional-interface
2个回答
2
投票

声明不等同。由于variable shadowing,第一种方法可以翻译为:

public static BiFunction<Integer, Integer, Integer> addTwoIntegers(Integer i1, Integer i2) {
    return (i1x, i2x) -> i1x + i2x;
}

第二种方法函数表达式是指addTwoIntegers2方法参数i1i2而不是函数参数i1xi2xi1是函数闭包中可用的i2,因为它们都是0,结果是0


1
投票

所以要么两个宣言不等同,这很难承认,

They are indeed not equivalent!

addTwoIntegers的方法参数,即i1i2在您的第一个样本中未使用。

public static BiFunction<Integer, Integer, Integer> addTwoIntegers(Integer i1, Integer i2) {
    // to aid to debugging
    System.out.println(String.format("In addTwoIntegers i1: %s, i2: %s", i1, i2)); 
    return new BiFunction<Integer, Integer, Integer>() {
        @Override
        public Integer apply(Integer i1, Integer i2) {
            // see the difference in value as you run
            System.out.println(String.format("In apply i1: %s, i2: %s", i1, i2)); 
            return i1 + i2;
        }
    };
}

为了进一步增加i1i2作为apply方法的方法参数的范围是匿名类中的方法的本地,这是您的代码所代表的。

Further Improvement

如果你要实现添加到Integers(并返回一个Integer),另一种更清洁的方法是在你可能重用实现的范围内定义一个BinaryOperator<Integer>

BinaryOperator<Integer> addTwoIntegers = Integer::sum; // (a,b) -> a+b

然后简单地用它作为

System.out.println("addTwoIntegers: " + addTwoIntegers.apply(5, 7));
© www.soinside.com 2019 - 2024. All rights reserved.