4

Given the following function:

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;
    }

Is there any way to consume all the predicates without having to loop through them and re-assign to the list? For instance, it'd be great if .stream() had a filter that took varargs, or some way to do that within a single stream.

Tagir Valeev
  • 97,161
  • 19
  • 222
  • 334
Jean
  • 670
  • 1
  • 5
  • 14

3 Answers3

4

I can suggest create one new predicate which combine all other:

Predicate<X> allPredicates = x -> Arrays.stream(predicates)
          .mapToInt(predicate -> !predicate.test(x)? 1: 0).sum()==0;
allProducts = allProducts.stream().filter(allPredicates).collect(toList());

EDIT Better way from @Holger answer How to apply multiple predicates to a java.util.Stream?

Predicate<X> allPredicates = Arrays.stream(predicates)
                                   .reduce(Predicate::and)
                                   .orElse(x->true);
Community
  • 1
  • 1
sibnick
  • 3,995
  • 20
  • 20
1

I'd write a method for combining many predicates into one.

@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;
    };
}

Then you can do:

allProducts.stream()
           .filter(allTrue(predicates))
           .collect(Collectors.toList());
Paul Boddington
  • 37,127
  • 10
  • 65
  • 116
0

It does. Streams are normal objects - you can store them in variables and such.

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

    return stream.collect(toList());
user253751
  • 57,427
  • 7
  • 48
  • 90
  • 1
    Using hypotetical `foldLeft` stream operation that would be the shortest solution: `Stream.of(predicates).foldLeft(allProducts.stream(), Stream::filter).collect(toList())`. Unfortunately there's no `foldLeft` yet... – Tagir Valeev Oct 02 '15 at 05:02
  • @TagirValeev Nested streams are a surefire way to confuse people, I'm sure. – user253751 Oct 02 '15 at 05:03