Novice User
Novice User

Reputation: 3824

Java stream get single element from collection

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?

Upvotes: 2

Views: 3873

Answers (3)

TJReinert
TJReinert

Reputation: 347

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.

Upvotes: 0

pxcv7r
pxcv7r

Reputation: 466

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);} );

Upvotes: 0

Andreas
Andreas

Reputation: 159086

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"); });

Upvotes: 3

Related Questions