Encodera

Thanks for reading!

Donate to the site — we work hard for you.

How to find the first element matching a condition

Short answer

filter() with findFirst() returns an Optional — a container that may or may not hold a result:

record User(int id, String name) {}
 
void main() {
    var users = List.of(new User(1, "Anna"), new User(2, "Oleg"));
 
    Optional<User> found = users.stream().filter(u -> u.id() == 2).findFirst();
    IO.println(found.map(User::name).orElse("not found"));
}

Output:

Oleg

When nothing is found

orElseThrow() throws if there is no element. It is convenient when absence is an error:

record User(int id, String name) {}
 
void main() {
    var users = List.of(new User(1, "Anna"));
 
    User user = users.stream().filter(u -> u.id() == 5).findFirst()
            .orElseThrow(() -> new NoSuchElementException("User 5 not found"));
}

Output:

Exception in thread "main" java.util.NoSuchElementException: User 5 not found

Performing an action

ifPresent() runs code only if the element is found:

void main() {
    var words = List.of("tree", "apple", "avocado");
    words.stream().filter(w -> w.startsWith("a")).findFirst().ifPresent(w -> IO.println("Found " + w));
}

Output:

Found apple

With a plain loop

A loop with return does the same and stops at the first match:

String firstLong(List<String> words) {
    for (String word : words) {
        if (word.length() > 4) {
            return word;
        }
    }
    return null;
}
 
void main() {
    IO.println(firstLong(List.of("tea", "coffee", "lemonade")));
}

Output:

coffee

Common mistake

Calling get() on an Optional without checking. If there is no element, it throws:

void main() {
    var words = List.of("tree");
    IO.println(words.stream().filter(w -> w.startsWith("a")).findFirst().get());
}

Output:

Exception in thread "main" java.util.NoSuchElementException: No value present

Functions used in this recipe

Thanks for reading!

Donate to the site — we work hard for you.