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

时间:2019-02-25 17:35:34

标签: java lambda java-8 anonymous-class functional-interface

在研究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

因此,这两个声明不相等,很难接受;或者,如果它们相等,则假定它们在相同的上下文中使用相同的参数被调用,它们应产生相同的结果。这不是矛盾之处吗?
在此先感谢可以遮挡某些灯光的人。
亲切的问候,尼古拉斯

2 个答案:

答案 0 :(得分: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 :(得分:1)

  

所以两个声明都不相等,这很难   承认,

它们确实不相等!

第一个示例中未使用addTwoIntegersi1i2 的方法参数。

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方法的方法参数是匿名类中该方法的本地代码,这就是您的代码所表示的。

进一步改进

如果要实现添加到Integer(并返回Integer)中,另一种更简洁的方法是在您要使用的范围内定义BinaryOperator<Integer>可能将实现重用为:

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

,然后将其简单地用作

System.out.println("addTwoIntegers: " + addTwoIntegers.apply(5, 7));