2

I am using a non stream way to get single element from collection.

List<MyCustomClass> list = OtherObject.getMyList();

if (list.size() != 1) {
throw new RuntimeException();
}

MyCustomClass customClass = list.get(0);

Instead of this multi liner approach, is there some way to achieve this via streams?

5
  • 3
    There's a way to get the first element, but there's no built-in way to assert that a stream has exactly one item; this isn't part of the use pattern of streams. Commented Apr 11, 2020 at 2:06
  • @chrylis-onstrike- That is incorrect. Commented Apr 11, 2020 at 2:39
  • @Andreas That isn't a built-in way to do it, and it is horrible in every imaginable way. Commented Apr 11, 2020 at 7:51
  • @Polygnome I never said it was pretty, but it is a way to achieve what OP wants, using streams. And it is built-in, the only custom code is the construction of the exceptions to throw. Or would you also say that sorting isn't built-in because it requires the user to supply the comparison (natural or explicit)? I'd disagree with that strict interpretation of "built-in". Commented Apr 11, 2020 at 10:44
  • @Andreas by your usage of built-in, everything you can possibly write in java is "built-in". need a CNN? Here is just some lines of code, this is all built in in Java... yeah no. Commented Apr 11, 2020 at 11:47

3 Answers 3

3

You can use reduce(accumulator) and orElseThrow(exceptionSupplier) to ensure the stream produces exactly one result.

MyCustomClass customClass = list.stream()
        .reduce((a,b) -> { throw new RuntimeException("Too many values present"); })
        .orElseThrow(() -> { throw new RuntimeException("No value present"); });
Sign up to request clarification or add additional context in comments.

2 Comments

This isn't built in, it's much less clear than the OP's original code, and it's much less efficient.
@chrylis-onstrike- reduce() and orElseThrow() are both built-in. OP didn't ask for cleaner/simpler code, only for a stream solution to do the same in a single statement ("one-liner").
0

I was looking for a version with a single collect statement, although it turned out not as concise or elegant as the solution by Andreas. It uses an implementation of Collector that accumulates to a one-element list, while the combiner raises an exception if we have more than one element; the finisher raises an exception when the list is empty.

list.stream().collect(
    Collector.of( ArrayList::new, 
                  (a, t) -> { if (!a.isEmpty())
                                  throw new RuntimeException();
                              a.add(t); },
                  (a, b) -> { throw new RuntimeException(); },
                  a -> { if( a.isEmpty() )
                             throw new RuntimeException();
                         return a.get(0);} );

Comments

0

You could try returning an optional from findFirst() or findAny().

List<String> strings = new ArrayList<>();

Optional<String> maybeFirst = strings.stream().findFirst();
// we now have an optional, lets force a value

String value = maybeFirst.orElseThrow(IllegalArgumentException::new);
// if there isn't a value, we'll throw an illegal argument exception.

This can collapsed into the following.

String value = strings.stream()
                      .findFirst()
                      .orElseThrow(() -> new IllegalArgumentException("There must be at least one string."));

Hope that helps.

4 Comments

Edited to remove such claim.
This answer does not handle the case when the list has more than one element.
That's fair. From the original question it seemed as though the check for exactly one element was just a way to ensure there would be some element to grab. Thats where using findAny or findFirst would come in handy.
But in the question, the condition to check is list.size() != 1 instead of list.isEmpty().

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.