I'm a big fan of the singleOrEmpty
stream operator. It's not in the std lib, but I find it very useful. If a stream has only a single value, it returns that value in an Optional
. If it has no values or more than one value, it returns Optional.empty()
.
Optional<Int> value = someList.stream().{singleOrEmpty}
[] -> Optional.empty()
[1] -> Optional.of(1)
[1, 1] -> Optional.empty()
etc.
I asked a question about it earlier and @ThomasJungblut came up with this great implementation:
public static <T> Optional<T> singleOrEmpty(Stream<T> stream) {
return stream.limit(2)
.map(Optional::ofNullable)
.reduce(Optional.empty(),
(a, b) -> a.isPresent() ^ b.isPresent() ? b : Optional.empty());
}
The only problem is, you have to put it at the beginning of your call
singleOrEmpty(someList.stream().filter(...).map(...))
rather than sequentially at the end
someList.stream().filter().map().singleOrEmpty()
which makes it harder to read than other stream mechanisms.
So as a newbie to this stream processing stuff, does anybody have any tricks for how to go about putting a short-circuiting singleOrEmpty
mechanism at the end of a sequence of stream transformations?
It will not be as fast as the one with limit(2) but you can use it as list.stream().filter(...).map(...).collect(singleOrEmpty())
static <T> Collector<T, ?, Optional<T>> singleOrEmpty() {
return Collectors.collectingAndThen(
Collectors.mapping(
Optional::of,
Collectors.reducing((a, b) -> Optional.empty())
),
o -> o.orElseGet(Optional::empty)
);
}
Stream.empty().collect(singleOrEmpty()); // Optional.empty
Stream.of(1).collect(singleOrEmpty()); // Optional[1]
Stream.of(1, 1).collect(singleOrEmpty()); // Optional.empty
Stream.of(1, 1).skip(1).collect(singleOrEmpty()); // Optional[1]
For what it's worth, unless this is really performance critical code, I would personally prefer the less clever but much clearer implementation
static<T> Collector<T,?,Optional<T>> singleOrEmpty() {
return Collectors.collectingAndThen(
Collectors.toList(),
lst -> lst.size() == 1
? Optional.of(lst.get(0))
: Optional.empty()
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With