javajava-streamcollectsupplier

what is a proper "supplier" for a "stream.collector" of EnumSet?


The following code does not compile:

    HashSet<Integer> nlsCandidates;         // added here to help read the stream coding below
    EnumSet<ScConstraint>[] rowConstraints; // added here to help read the stream coding below
    EnumSet<ScConstraint> tbd = nlsCandidates.stream()
        .flatMap(p -> rowConstraints[10*k + p].stream())
        .filter(cstr -> !s.contains(cstr.RC))
        .collect(EnumSet.noneOf(ScConstraint.class), (c, cstr) -> c.add(cstr), EnumSet::addAll);

This is the error message:

no suitable method found for collect(EnumSet<ScConstraint>,(c,cstr)->[...]cstr),EnumSet::addAll)
        .collect(EnumSet.noneOf(ScConstraint.class), (c, cstr) -> c.add(cstr), EnumSet::addAll);
        ^
method Stream.<R#1>collect(Supplier<R#1>,BiConsumer<R#1,? super ScConstraint>,BiConsumer<R#1,R#1>) is not applicable
  (cannot infer type-variable(s) R#1
    (argument mismatch; no instance(s) of type variable(s) E exist so that EnumSet<E> conforms to Supplier<R#1>))

method Stream.<R#2,A>collect(Collector<? super ScConstraint,A,R#2>) is not applicable
  (cannot infer type-variable(s) R#2,A
    (actual and formal argument lists differ in length))

where R#1,T,E,R#2,A are type-variables:
R#1 extends Object declared in method <R#1>collect(Supplier<R#1>,BiConsumer<R#1,? super T>,BiConsumer<R#1,R#1>)
T extends Object declared in interface Stream
E extends Enum<E> declared in method <E>noneOf(Class<E>)
R#2 extends Object declared in method <R#2,A>collect(Collector<? super T,A,R#2>)
A extends Object declared in method <R#2,A>collect(Collector<? super T,A,R#2>)

I need the Supplier to return an empty EnumSet. How can I achieve that?


Solution

  • The first argument of the tree-args flavor of Stream.collect() is of type Supplier. It's a function which is meant to provide a mutable object, that would be used to accumulate stream elements and would be returned as the result of the stream execution.

    As it was mentioned by @MauricePerry in the comments, you've provided a value, i.e. an EnumSet itself, not a Supplier of an EnumSet. Therefore, you're getting a compilation error due to the mismatch of type of the argument and expected type.

    The correct code can be written like this:

    EnumSet<ScConstraint> tbd = nlsCandidates.stream()
        .flatMap(p -> rowConstraints[10 * k + p].stream())
        .filter(cstr -> !s.contains(cstr.RC))
        .collect(
            () -> EnumSet.noneOf(ScConstraint.class),
            Set::add,
            Set::addAll
        );
    

    Alternatively, you can make use of the collect() version expecting an instance of Collector as an argument. And as a Collector, you can provide toCollection() (credits to @Holger):

    EnumSet<ScConstraint> tbd = nlsCandidates.stream()
        .flatMap(p -> rowConstraints[10 * k + p].stream())
        .filter(cstr -> !s.contains(cstr.RC))
        .collect(Collectors.toCollection(
            () -> EnumSet.noneOf(ScConstraint.class)
        ));