Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

In this short tutorial, we’ll explain how to avoid NoSuchElementException when working with the Stream API.

First, we’re going to explain the main cause of the exception. Then, we’ll showcase how to reproduce and fix it using practical examples.

2. The Cause of the Exception

Before delving deep into the details, let’s understand what the exception means.

In short, NoSuchElementException is thrown to signal that the requested element doesn’t exist. For instance, trying to access an element that is not available or present will lead to this exception.

Typically, calling the get() method on an empty Optional instance is one of the most common causes of NoSuchElementException when working with the Stream API.

3. Producing the Exception

Now that we know what the exception is, let’s go down the rabbit hole and see how to reproduce it in practice.

For example, let’s create a list of names and filter it using the Stream API:

@Test(expected = NoSuchElementException.class)
public void givenEmptyOptional_whenCallingGetMethod_thenThrowNoSuchElementException() {
    List<String> names = List.of("William", "Amelia", "Albert", "Philip");
    Optional<String> emptyOptional = names.stream()
      .filter(name -> name.equals("Emma"))
      .findFirst();

    emptyOptional.get();
}

As we can see, we used the filter() method to find the name “Emma”. Furthermore, we chained with the findFirst() method to get an Optional containing the first found element or an empty Optional if the filtered stream is empty.

Here, our list doesn’t contain the name “Emma”, so findFirst() returns an empty Optional. The test case fails with the NoSuchElementException exception because we’re trying to get a name that doesn’t exist and an empty Optional doesn’t hold any value.

4. Avoiding the Exception

Now, let’s see how to fix the exception. The easiest way would be to check if there’s a value present in our Optional instance before calling the get() method.

Fortunately, the Stream API provides the isPresent() method specifically for this purpose. So, let’s see it in action:

@Test
public void givenEmptyOptional_whenUsingIsPresentMethod_thenReturnDefault() {
    List<String> names = List.of("Tyler", "Amelia", "James", "Emma");
    Optional<String> emptyOptional = names.stream()
      .filter(name -> name.equals("Lucas"))
      .findFirst();

    String name = "unknown";
    if (emptyOptional.isPresent()) {
        name = emptyOptional.get();
    }

    assertEquals("unknown", name);
}

Here, we used isPresent() to make sure that there’s a value inside our Optional instance before calling the get() method. That way, we avoid the NoSuchElementException exception.

Please notice that the use of isPresent() comes with the cost of the if-else statements. So, can we do it better? Yes!

Typically, the best way to go is to use the orElse() method. In short, this method returns the value if it’s present, or the given fallback argument otherwise:

@Test
public void givenEmptyOptional_whenUsingOrElseMethod_thenReturnDefault() {
    List<String> names = List.of("Nicholas", "Justin", "James");
    Optional<String> emptyOptional = names.stream()
      .filter(name -> name.equals("Lucas"))
      .findFirst();

    String name = emptyOptional.orElse("unknown");

    assertEquals("unknown", name);
}

As shown above, this method offers a more convenient and straightforward way to avoid NoSuchElementException.

Alternatively, we can use the orElseGet() method to achieve the same outcome:

@Test
public void givenEmptyOptional_whenUsingOrElseGetMethod_thenReturnDefault() {
    List<String> names = List.of("Thomas", "Catherine", "David", "Olivia");
    Optional<String> emptyOptional = names.stream()
      .filter(name -> name.equals("Liam"))
      .findFirst();

    String name = emptyOptional.orElseGet(() -> "unknown");

    assertEquals("unknown", name);
}

Unlike orElse(), orElseGet() accepts a supplier as a parameter. Another key difference is that orElse() is executed in all cases, even if the Optional instance has a value. However, orElseGet() is only executed when the Optional value isn’t present.

Please note that our article on the difference between the orElse() and orElseGet() methods does a great job of covering the topic.

5. Best Practices to Avoid NoSuchElementException

In a nutshell, there are several key points to keep in mind when working with the Stream API to avoid the NoSuchElementException exception:

  • Always check if the returned stream/optional is not empty before calling the get() method.
  • Try to define a fallback value using orElse() or orElseGet().
  • Use a filter before calling any terminal operation on a stream.

6. Conclusion

In this short article, we explored different ways of avoiding the exception NoSuchElementException when working with the Stream API.

Along the way, we illustrated how to reproduce the exception and how to avoid it using practical examples.

As always, the full source code of the examples is available over on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.