0

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));
Peters_
  • 597
  • 2
  • 8
  • 28
  • 2
    what does those `...` implement and `return` and what is the return type of `getCode` and `findXYZ`? – Naman Jul 16 '20 at 18:15
  • 1
    he mentioned that the return type of those 'return' and findXyz is List – lorraine batol Jul 16 '20 at 18:22
  • 1
    I’d find it easier to help if you gave us [a reproducible example](https://stackoverflow.com/help/minimal-reproducible-example), that is, one that gives that exact error message. – Ole V.V. Jul 16 '20 at 18:40

2 Answers2

1

(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(...));`
    
lorraine batol
  • 6,001
  • 16
  • 55
  • 114
0

Just add a .get() after orElseGet()

private List<User> findUsers(...)
{
    ...
    return usersData.stream() //userData is another list of objects 
           .findFirst()
           .map(this::getCode)
           .map(code-> {
               if (...) {
                   return ...
               }
               else {
                   return ...;
               }
           })
           .orElseGet(() -> findXYZ(...))
           .get(); 
}

Because .orelse get return object of Optional class

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Dhruv Tailor
  • 2,498
  • 1
  • 7
  • 10
  • is it possible to return the element itself(code) after stream from orElseGet()? – Dev Aug 19 '21 at 15:09