java – Filters Java Stream on 1 and only 1 element

Update

Nice tip in @Holger’s comment:

Optional<User> match = users.stream()
              .filter((user) -> user.getId() > 1)
              .reduce((u, v) -> { throw new IllegalStateException("More than one ID found") });

Original answer

The exception is thrown by Optional#get, but if you have more than one item that won’t help you. You can collect users in a collection that accepts only one item, for example:

User match = users.stream().filter((user) -> user.getId() > 1)
                  .collect(toCollection(() -> new ArrayBlockingQueue<User>(1)))
                  .poll();

which throws a Java.lang.IllegalStateException: Queue fullbut it looks too hacky.

Or you could use a reduction combined with an optional option:

User match = Optional.ofNullable(users.stream().filter((user) -> user.getId() > 1)
                .reduce(null, (u, v) -> {
                    if (u != null && v != null)
                        throw new IllegalStateException("More than one ID found");
                    else return u == null ? v : u;
                })).get();

The reduction essentially returns:

  • null if no user is found
  • the user if only one is found
  • throws an exception if more than one is found

The result is then wrapped in an optional.

But the simplest solution would probably be to just collect one collection, verify that its size is 1, and get the only item.

Leave a comment