所以假设我在流上使用一些随机过滤器,最直接的方法是直接输入谓词:
x.stream().filter(e -> e % 2 == 0)
我也可以简单地参考并提前定义谓语:
Predicate<Integer> isEven = e -> e % 2 == 0;
...
x.stream().filter(isEven)
但我也可以使用一个函数:
private static boolean isEven(Integer integer) {
return integer % 2 == 0;
}
...
x.stream().filter(MyClass::isEven)
据我所知,谓语当然要有限得多,而函数可能会有副作用等。但是因为像文卡特·苏布拉曼尼亚这样的人使用后一种解决方案,我真的很想知道:这里的主要区别是什么?
不!与方法引用相比,谓词并没有真正的限制!事实上,这些东西都是一样的!
只需查看filter()
函数签名:filter(谓语
让我们考虑一下你的例子:
x.stream(). filter(e-
Predicate<Integer> isEven = e -> e % 2 == 0;
...
x.stream().filter(isEven)
第一个只是后者的内联版本。
private static boolean isEven(Integer integer) {
return integer % 2 == 0;
}
...
x.stream().filter(MyClass::isEven)
在这里,您可以看到方法引用
正在运行。MR只是一个语法糖,允许您根据已经存在的函数定义Lambda表达式。
最终,所有这些表达式都成为Predicate功能接口的相同实现。
此外,您还可以通过在右侧使用块语法在Lambda表达式中执行副作用,但通常不建议这样做:
e -> {
//side effects here
return e % 2 == 0;
}
从构建可重用谓词库的角度来看,返回布尔值的函数库远比静态最终谓词实例库更通用。为什么?
考虑一个包含以下内容的库:
public static boolean isEven(int i) { return i -> i % 2 == 0; }
vs.
public static final Predicate<Integer> IS_EVEN = i -> i % 2 == 0;
filter(MyLib::is甚至)
比filter(i-
同样的推理适用于所有函数类型。编写函数。它们可以应用于任何与简单方法引用匹配签名的函数类型。
两者都将返回过滤后的流。使用谓词(返回true或false的函数)更具可读性……这是上面使用Function的简短介绍。
public class Demo {
public static Function<Integer, Predicate<Integer>> isGreaterThanNumberIamAboutToApply = pivot -> number -> number % pivot == 0;
public static void main(String[] args) {
List<Integer> myInts = Arrays.asList(new Integer[]{1, 2, 3, 5, 6, 7, 7})
.stream()
.filter(isGreaterThanNumberIamAboutToApply
.apply(3)).collect(Collectors.toList());
myInts.forEach(x -> System.out.printf("%s\n", x));
}
}