The easiest solution (except leaving everything as is which is even easier) is to create three separate streams:
Set<MyObj> set1 = inputSet.stream().filter(pred1).collect(Collectors.toSet());
Set<MyObj> set2 = inputSet.stream().filter(pred2).collect(Collectors.toSet());
Set<MyObj> set3 = inputSet.stream().filter(pred3).collect(Collectors.toSet());
If you have a List of predicates, you can create a corresponding List of sets as a result:
List<Predicate<MyObj>> predicates = Arrays.asList(pred1, pred2, pred3);
List<Set<MyObj>> result = predicates.stream()
.map(pred -> inputSet.stream().filter(pred).collect(Collectors.toSet()))
.collect(Collectors.toList());
Here the first set in the resulting list corresponds to the first predicate and so on.
If you really want to process your input in single pass (for whatever reason), you may write a special collector for this. Here's one which is quite universal:
public static <T, A, R> Collector<T, ?, List<R>> multiClassify(
List<Predicate<T>> predicates, Collector<? super T, A, R> downstream) {
Supplier<A> dsSupplier = downstream.supplier();
BiConsumer<A, ? super T> dsAccumulator = downstream.accumulator();
BinaryOperator<A> dsCombiner = downstream.combiner();
Supplier<List<A>> supplier = () -> Stream.generate(dsSupplier)
.limit(predicates.size()).collect(Collectors.toList());
BiConsumer<List<A>, T> accumulator = (list, t) -> IntStream
.range(0, predicates.size()).filter(i -> predicates.get(i).test(t))
.forEach(i -> dsAccumulator.accept(list.get(i), t));
BinaryOperator<List<A>> combiner = (l1, l2) -> IntStream.range(0, predicates.size())
.mapToObj(i -> dsCombiner.apply(l1.get(i), l2.get(i)))
.collect(Collectors.toList());
Characteristics[] dsCharacteristics = downstream.characteristics().toArray(
new Characteristics[0]);
if (downstream.characteristics().contains(Characteristics.IDENTITY_FINISH)) {
@SuppressWarnings("unchecked")
Collector<T, ?, List<R>> result = (Collector<T, ?, List<R>>) (Collector<T, ?, ?>)
Collector.of(supplier, accumulator, combiner, dsCharacteristics);
return result;
}
Function<A, R> dsFinisher = downstream.finisher();
Function<List<A>, List<R>> finisher = l -> l.stream().map(dsFinisher)
.collect(Collectors.toList());
return Collector.of(supplier, accumulator, combiner, finisher, dsCharacteristics);
}
It takes a list of predicates and returns list of downstream collector results for each predicate. Usage example:
List<String> input = asList("abc", "ade", "bcd", "cc", "cdac");
List<Predicate<String>> preds = asList(
s -> s.length() == 3,
s -> s.startsWith("a"),
s -> s.endsWith("c"));
List<Set<String>> result = input.stream().collect(multiClassify(preds, Collectors.toSet()));
// [[bcd, abc, ade], [abc, ade], [cc, abc, cdac]]