使用Predicate或函数作为Java流过滤器有什么区别?

时间:2016-04-22 16:16:16

标签: java-8 java-stream predicate

所以假设我在流上使用了一些随机过滤器,最直接的方法就是直接输入Predicate:

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)

据我所知,Predicate当然更有限,而功能可能有副作用等。但是由于像Venkat Subramaniam这样的人使用后一种解决方案,我真的很想知道:这里的主要区别是什么?

3 个答案:

答案 0 :(得分:12)

没有!与方法参考相比,谓词并没有真正的限制!事实上,这些都是一样的!

只需查看filter()函数签名: filter(Predicate<? super T> predicate)

让我们考虑你的例子:

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)

在这里,您可以看到Method References正在行动中。 MR只是一种语法糖,允许您根据已有的函数定义Lambda Expression。

在一天结束时,所有这些表达式都成为Predicate功能界面的相同实现。

此外,您还可以在右侧使用块语法在Lambda表达式中执行副作用,但通常不建议这样做:

e -> {
    //side effects here
    return e % 2 == 0;
}

答案 1 :(得分:4)

从构建可重用谓词库的角度来看它时,返回布尔值的函数库是比静态最终谓词实例库更通用的谓词集合。为什么呢?

考虑包含以下内容的库:

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::isEven)filter(i -> i % 2 == 0)更容易扫描,而filter(MyLib::isEven)会告诉您确切调用的内容,而filter(MyLib.IS_EVEN)则不会
  • 如果您只是想调用库函数而不是将其用作谓词,那么它更具可读性。 MyLib.isEven(i)扫描效果优于MyLib.IS_EVEN.test(i)
  • 如果您需要使用IntPredicate代替Predicate<Integer>一个Guava Predicate<Integer>,Apache Collections4 Predicate<Integer>等,使用库函数,您只需继续{ {1}}。使用MyLib::isEven实例,您必须通过执行static final Predicate<Integer>来转换它(最后您最终使用方法参考)

同样的推理适用于所有功能类型。写功能。它们可以应用于任何与签名匹配的函数类型和简单的方法引用。

答案 2 :(得分:0)

两者都将返回经过过滤的流。使用谓词(返回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));

    }

}