A situation I find myself in from time to time is needing to filter a List down to what I expect to be either a single element or nothing.

What I’m aiming for is to be able to do something like this …

return states.stream()
        .filter(State::isActive())
        .collect(toOptional())
        .orElseThrow();

Lets get started. I’m going to implement this as a static helper …

public class StreamUtils {
    private StreamUtils() { }

    // TODO
}

Clearly we’re going to need to be able to reduce a Collection down to a single Optional element …

private static <T> Optional<T> findOnly(Collection<T> collection) {
    if (collection.size() > 1) {
        throw new IllegalStateException("Expected zero or one element");
    }
    return collection.stream().findFirst();
}

Now we need to define a Collector, something like toList()

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

Right, now what? Well we have a stream and a method that will take a Collection and reduce it to a single element, so all thats left is to tie the two together. One way to do this is to use toList and then operate on the result - which is exactly what collectingAndThen will allow us to do …

public static <T> Collector<T, ?, Optional<T>> toOptional() {
    return collectingAndThen(toList(), StreamUtils::findOnly);
}

And there we have it - done!

Bonus Round

For cases where null would be preferable to an empty Optional

public static <T> Collector<T, ?, T> toNullable() {
    return collectingAndThen(toList(), l -> findOnly(l).orElse(null));
}