I have three Optional> which have to be combined and returned. I tried to use Optional.map()
and flatmap()
but was not successful.
I suggest that you don’t want to return an Optional
from your method. In case there are no records in any of the three entity lists, the caller would prefer just to have an empty list.
public List<Entity> getRecords() {
return Stream.of("1", "2", "3")
.map(repo::findAllByStatus)
.flatMap(el -> el.map(List::stream).orElse(Stream.empty()))
.collect(Collectors.toList());
}
A couple of the other answers use isPresent
and get
. They are low-level, and we don’t need them here.
We don’t absolutely need the stream operation, though. Here’s a possibility without it:
public List<Entity> getRecords() {
List<Entity> concatenation = new ArrayList<>();
repo.findAllByStatus("1").ifPresent(concatenation::addAll);
repo.findAllByStatus("2").ifPresent(concatenation::addAll);
repo.findAllByStatus("3").ifPresent(concatenation::addAll);
return concatenation;
}
Something like :
return Optional.of(Stream.of(entity1.orElse(new ArrayList<>()), entity2.orElse(new ArrayList<>()), entity3.orElse(new ArrayList<>()))
.flatMap(List::stream)
.collect(Collectors.toList()));
or rather more readable as :
return Optional.of(Stream.of(entity1, entity2, entity3)
.filter(Optional::isPresent)
.map(Optional::get)
.flatMap(List::stream)
.collect(Collectors.toList()));
It gets easier when you use a stream:
return Stream.of(entity1, entity2, entity3)
.filter(Optional::isPresent)
.map(Optional::get)
.flatMap(List::stream)
.collect(Collectors.collectingAndThen(Collectors.toList(), Optional::of));
Important to note that this optional won't ever be empty. It will contain at least an empty list, which defeats the purpose of using optionals. When using Collection
types as return types, Optional
are not really used because it's recommended to return an empty collection where an empty optional would be used.
So I would just change the method's return type to List
and let the stream return an empty list when no input optional is present.