Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Defaulting Optional orElse with Optional.empty in Java 8

Java 8 here. I need to search two lists of POJOs for a string and want to use the Stream/Optional APIs correctly.

If the name appears in the first list ("lunches") then I want to return an optional containing it. Else, if the name appears in the second list ("dinners") then I want to return an optional containing it. Otherwise I want to return Optional.empty() if the name doesn't existing in either list. My best attempt thus far:

public class Restaurant {

    private String id;
    private String name;
    private List<Food> lunches;
    private List<Food> dinners;

    public Optional<Food> findFoodByName(String name) {

        return Optional.of(lunches.stream()
                                  .filter(food -> food.getName()
                                                      .equalsIgnoreCase(name))
                                  .findFirst())
                       .orElse(dinners.stream()
                                      .filter(food -> food.getName()
                                                          .equalsIgnoreCase(name))
                       .findFirst());
//                     .orElse(null);        TODO: how to return empty optional if neither in 'lunches' nor 'dinners'?

    }

}

Can anyone help me cross the finish line here?

like image 817
hotmeatballsoup Avatar asked Jan 22 '20 21:01

hotmeatballsoup


2 Answers

Combine both the list using Stream.of and check for element or return Optional.empty()

Stream.of(lunches, dinners)
      .flatMap(List::stream)
      .filter(s -> s.getName()
                    .equalsIgnoreCase(name))
      .findFirst();

As per the suggestion from @Holger you can also use Stream.concat to concat two streams and then check for element

Stream.concat(lunches.stream(), dinners.stream())
      .filter(s -> s.getName()
                    .equalsIgnoreCase(name))
      .findFirst();
like image 138
Deadpool Avatar answered Sep 22 '22 04:09

Deadpool


You can do like this too:

 Optional<Food> firstTry = lunches.stream()
                                  .filter(f -> f.getName().equalsIgnoreCase(name))
                                  .findFirst();
 return firstTry.map(Optional::of)
                .orElse(dinners.stream()
                        .filter(f -> f.getName().equalsIgnoreCase(name)).findFirst());

Or in Java9

firstTry.or(() -> dinners.stream().filter(s -> s.equalsIgnoreCase(name)).findFirst());

As @Slaw commented correctly use of orElseGet() avoid eagerly computing.

Optional<Food> firstTry = lunches.stream().filter(...)...findFirst();
Supplier<Optional<Food>> secondTry = () -> dinners.stream()...findFirst();

and at the end

return firstTry.map(Optional::of).orElseGet(secondTry);
like image 45
Hadi J Avatar answered Sep 22 '22 04:09

Hadi J