4

I have some experience with C#'s LINQ and am trying to learn Java 8's stream API. Now in LINQ I regularly use the Single() Method, which picks the one-and-only object out of a sequence and throws an exception if there isn't a one-and-only object in the stream.

Now:

  • Am I correct in thinking Java 8's streams don't have such a method?
  • Is there a preferred alternative of getting this functionality?
  • Is it good idea to implement this myself?
4
  • Indeed sort of answers my questions 1) methods isn't there out of the box 2) lots of options, no consensus about what is preferred, custom collector looks nice 3) implementing a custom collector is what people are suggesting. So thanks for the link, searched for it but apparently not good enough. Any action required from me to confirm this as a duplicate? Commented Mar 5, 2015 at 18:01
  • There's also the answer from Brian Goetz you should consider (either by wrapping it in a simple utility method); or with the Guava Iterators utility class; which have the Single behavior you are looking for. T elem = Iterators.getOnlyElement(stream.iterator()); Commented Mar 5, 2015 at 18:17
  • 1
    stream.collect(Collectors.toMap(()->"single", Functions.identity()).get("single") will also throw if there is more than one element… Commented Mar 5, 2015 at 18:32
  • Stream now has findFirst - returns an Optional (instead of signalling no element by throwing). Don't know in which version it was introduced, but it is there in 17. Commented Jul 8, 2023 at 3:36

1 Answer 1

4

Here's one way to get this functionality:

Stream<String> stream = Stream.of ("first");
String single = stream.reduce((a,b)->{throw new SomeException();})
                      .get();

The idea is that if there's more than one element, reduce would throw the exception inside the lambda expression. If there are no elements, get() would throw NoSuchElementException.

You can also change the exception thrown when there are no elements by changing the code to :

Stream<String> stream = Stream.of ("first");
String single = stream.reduce((a,b)->{throw new SomeException();})
                      .orElseThrow(SomeException::new);
Sign up to request clarification or add additional context in comments.

1 Comment

Why this works is: the associative accumulation function used for the reduction is only called by the stream if there are multiple elements. If there is a single element, the stream resolves to that element. We hijack this feature to throw an exception instead of accumulating the values. It's clever and concise but may confuse, since it's not how the API was intended to be used.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.