在Java 8中应用一系列过滤器是否有优雅的方法?

Zac*_*ack 3 java reduce lambda java-8 java-stream

有没有办法使用reduce或类似的方法将一组过滤器应用于对象数组?

现在,我有这个:

private void applyManyFilters(long[] initialData, LongPredicate... filters) {
    LongStream stream = Arrays.stream(initialData);
    for (LongPredicate filter : filters) {
      stream = stream.filter(filter);
    }
    long[] dataToUse = stream.toArray();

    // Use filtered data
}
Run Code Online (Sandbox Code Playgroud)

更优雅的解决方案看起来像这样:

private void applyManyFilters(long[] initialData, LongPredicate... filters) {
    long[] dataToUse = Arrays.stream(filters).reduce(Arrays.stream(initialData), (a, b) -> a.filter(b)).toArray();

    // Use filtered data here
}
Run Code Online (Sandbox Code Playgroud)

当然,上面的例子不能编译,因为两个参数都reduce需要,而LongPredicate不是LongStream.我很好奇上面的代码是否可以写成一行?

(PS为了清楚起见,这是一个关于Java 8如何工作的问题,而不是关于样式的问题.我同意单行方法几乎不像循环一样可读.)

And*_*eas 6

我相信这就是你要找的东西:

private void applyManyFilters(long[] initialData, LongPredicate... filters) {
    long[] dataToUse = Arrays.stream(initialData)
                             .filter(v -> Arrays.stream(filters)
                                                .allMatch(f -> f.test(v)))
                             .toArray();
    // Use filtered data
}
Run Code Online (Sandbox Code Playgroud)

UPDATE

合并其他两个答案,您还可以创建一个帮助方法来组合过滤器数组.你可以做的是,在你的代码的任何一个辅助类重用一个很好的工具方法,与覆盖了其它谓词一起(BiPredicate,DoublePredicate,IntPredicatePredicate).

private void applyManyFilters(long[] initialData, LongPredicate... filters) {
    long[] dataToUse = Arrays.stream(initialData)
                             .filter(combine(filters))
                             .toArray();
    // Use filtered data
}
public static LongPredicate combine(LongPredicate... filters) {
    return Arrays.stream(filters)
                 .reduce(LongPredicate::and)
                 .orElse(x -> true);
}
Run Code Online (Sandbox Code Playgroud)

  • @flkes拥有`LongPredicate`的全部目的是在上面的代码中没有任何内容,例如第一个例子中的`v`和第二个例子中的`x`都是`long`,而不是`long` .你认为拳击发生在哪里? (2认同)
  • @flkes不,[`Arrays.stream(long [] array)`](https://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#stream-long:A- )返回[`LongStream`](https://docs.oracle.com/javase/8/docs/api/java/util/stream/LongStream.html).检查过载. (2认同)

Mar*_*ers 5

解决方案reduce是使用LongPredicate::and如下所示的方法将谓词缩减为单个谓词:

//prints 6
public static void main(String[] args) {
    applyManyFilters(new long[]{1, 2, 3, 4, 5, 6}, l -> l % 2 == 0, l -> l % 3 == 0);
}

private static void applyManyFilters(long[] initialData, LongPredicate... filters) {
    Arrays.stream(initialData).filter(
            Arrays.stream(filters).reduce(l -> true, LongPredicate::and)
    ).forEach(System.out::println);
}
Run Code Online (Sandbox Code Playgroud)