在研究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
因此,要么两个声明不等同,要么难以承认,或者,如果它们是等价的,假定它们在相同的上下文中具有相同的参数,则它们应该产生相同的结果。这不是一个不一致吗? 非常感谢能在这里遮挡一些光线的人。 亲切的问候,尼古拉斯
声明不等同。由于variable shadowing,第一种方法可以翻译为:
public static BiFunction<Integer, Integer, Integer> addTwoIntegers(Integer i1, Integer i2) {
return (i1x, i2x) -> i1x + i2x;
}
第二种方法函数表达式是指addTwoIntegers2
方法参数i1
和i2
而不是函数参数i1x
和i2x
。 i1
是函数闭包中可用的i2
,因为它们都是0
,结果是0
。
所以要么两个宣言不等同,这很难承认,
addTwoIntegers
的方法参数,即i1
和i2
在您的第一个样本中未使用。
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;
}
};
}
为了进一步增加i1
和i2
作为apply
方法的方法参数的范围是匿名类中的方法的本地,这是您的代码所代表的。
如果你要实现添加到Integer
s(并返回一个Integer
),另一种更清洁的方法是在你可能重用实现的范围内定义一个BinaryOperator<Integer>
:
BinaryOperator<Integer> addTwoIntegers = Integer::sum; // (a,b) -> a+b
然后简单地用它作为
System.out.println("addTwoIntegers: " + addTwoIntegers.apply(5, 7));