Search code examples
javagenericsjava-streamcollectors

Java collector to Optional<T>


Using Java streams and generics I'm trying to create a Collector, that would return me Optional.empty, if stream is empty, Optional<T> if stream has one item and throw exception if stream has more than one item.

public static <T, R extends Optional<T>> Collector<T, ?, R> toOptional() {
    return Collectors.collectingAndThen(
            Collectors.toList(),
            list -> {
                if (list.size() > 1) {
                    throw new CollectingException("More than one item found in: " + list);
                }
                if (list.size() == 1) {
                    return Optional.of(list.get(0));
                }
                return Optional.empty();
            }
    );
}

However I'm getting an error I don't understand.

Required type:
Collector<T,?,R>
Provided:
Collector<Object,Object,Object>
no instance(s) of type variable(s) T exist so that Optional<T> conforms to R inference variable RR has incompatible bounds: equality constraints: R lower bounds: Optional<T1868063>

The desired usage would be

List<Person> people = new ArrayList<>();
Optional<Person> john = people.stream().filter(person->"John".equals(person.getName())).collect(toOptional());

Could anyone please explain me what's wrong?


Solution

  • The declaration of your method is not correct, instead of:

    public static <T, R extends Optional<T>> Collector<T, ?, R> toOptional() {
    

    You can just use:

    public static <T> Collector<T, ?, Optional<T>> toOptional() {
    

    In other words, the method need to return an Optional object of type T directly, instead of using a separate type parameter R that extends Optional<T>.