Search code examples
lambdajava-8java-streamoption-typefindfirst

How to properly use the combination of .map and .orElseGet within stream API?


I have the following code:

private List<User> findUsers(...) {
...

    return usersData.stream() //userData is another list of objects
        .findFirst()
        .map(this::getCode)
        .map(code-> {
            if (...) {
                Optional<AnotherObject> anotherObject = getAnotherObject();
                return anotherObject.map(userService::getUsersFromAnotherObject) // getUsersFromAnotherObject returns List<User> but the whole line returns Optional of List<User>
            } else {
                ...
                return null;
            }
        }).orElseGet(() -> findXYZ(...));
}

which does not compile and says:
"Bad return type in lambda expression: List<User> cannot be converted to Optional<List<User>>"
even though findXYZ and all other if/else statements return in fact type List.

Could anybody explain to me what is wrong with the code?

EDIT: Sorry, I noticed that one of if statements is actually returning the Optional of List

If anybody is interested, I solved it simply editing the first "if" to:

return userService.getUsersFromAnotherObject(anotherObject.orElse(null));

Solution

  • (edited)

    In your case, the return of the two should match because that's the use of the orElseGet() - to give an alternate value of the same type.

    .map(code -> return ...)
    .orElseGet(() -> return ...)
    

    There are two options in your case:

    1. since your map() returns Optional<List<User>>, you can update the findXyz() to return the same

    2. update code of map() to something like below (return List<User> without Optional wrap, then you can keep your findXyz() in it's original).

           usersData.stream().findFirst()
           .map(this::getCode)
           .map(code-> {
               if (...) {
                   Optional<AnotherObject> anotherObject = getAnotherObject();
                   Optional<List<User>> optUserList = anotherObject.map(userService::getUsersFromAnotherObject)
                   return optUserList.isPresent() ? optUserList.get() : null;
               } else {
                       ...
                   return null;
               }
           }).orElseGet(() -> findXYZ(...));`