Java 8流中的可变谓词

4

给定以下函数:

public static <X> List<X> filterWithVarargPredicates(
        List<X> allProducts,
        Predicate<X>... predicates
    ) {
        for (Predicate<X> predicate : predicates) {
            allProducts = allProducts.stream()
                .filter(predicate)
                .collect(toList());
        }

        return allProducts;
    }

有没有一种方法可以消耗所有谓词而不必通过循环并重新分配给列表?例如,如果.stream()具有接受可变参数的过滤器,或者在单个流中以某种方式执行该操作,那将是非常好的。

3个回答

4
我可以建议创建一个新的谓词,将所有其他谓词组合起来:
Predicate<X> allPredicates = x -> Arrays.stream(predicates)
          .mapToInt(predicate -> !predicate.test(x)? 1: 0).sum()==0;
allProducts = allProducts.stream().filter(allPredicates).collect(toList());

编辑 @Holger的答案提供了更好的方法如何将多个谓词应用于java.util.Stream?

Predicate<X> allPredicates = Arrays.stream(predicates)
                                   .reduce(Predicate::and)
                                   .orElse(x->true);

1
我会写一个方法来将多个谓词组合成一个。
@SafeVarargs
static <T> Predicate<T> allTrue(Predicate<? super T>... predicates) {
    return t -> {
        for (Predicate<? super T> predicate : predicates)
            if (!predicate.test(t))
                return false;
        return true;
    };
}

然后你可以执行:
allProducts.stream()
           .filter(allTrue(predicates))
           .collect(Collectors.toList());

如果你有更多的谓词,那是一个很好的解决方案。 - Holger

0

没错。流是普通对象 - 你可以将它们存储在变量中等等。

    Stream<X> stream = allProducts.stream();
    for (Predicate<X> predicate : predicates) {
        stream = stream.filter(predicate);
    }

    return stream.collect(toList());

1
使用假设的 foldLeft 流操作,这将是最短的解决方案:Stream.of(predicates).foldLeft(allProducts.stream(), Stream::filter).collect(toList())。不幸的是,目前还没有 foldLeft - Tagir Valeev
@TagirValeev 嵌套流肯定会让人困惑,我敢肯定。 - user253751

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接