Reputation: 1581
How can I use the collect
method to collect within a nested ifPresent
method?
So far this is what I have:
List result = list.stream()
.findFirst()
.ifPresent(info -> {
info.getMap()
.stream()
.filter( entry -> entry.getKey().equals("test"))
.map(entry::getValue)
.collect(Collectors.toList())
});
Upvotes: 2
Views: 5708
Reputation: 19926
You might wanted to do this:
List result = list.stream()
.limit(1)
.flatMap(info -> // <-- removed brace {
info.getMap().stream()
.filter( entry -> entry.getKey().equals("test"))
.map(entry::getValue)
) // <-- removed brace here too
.collect(Collectors.toList());
Let me explain:
.limit(1)
: limits the stream only to the first element (or returns an empty stream if initial stream is empty)
.flatMap()
: maps the stream into a new stream. in this case a new stream consisting of values from Entry#getValue()
is returned
.collect(Collectors.toList())
: at last the stream of values is collected into a list.
As Olivier Grégoire said in the comments, the following does work too:
List result = list.stream()
.limit(1)
.flatMap(info -> info.getMap().stream())
.filter( entry -> entry.getKey().equals("test"))
.map(entry::getValue)
.collect(Collectors.toList());
Which in my opinion is more readable and clearer indicates what the intents were.
Upvotes: 4
Reputation: 828
It looks like you have a List<Info>
containing zero or more Info
s, where Info
is some object which has a getMap()
method returning a Map<String, Something>
and you want to end up with a List<Something>
, which is all the values of the first list item's map which have the key test.
You want to map
the optional instead of using ifPresent
. ifPresent
is a terminal operation which doesn't return anything (just executes code).
list // List<Info>
.stream() // Stream<Info>
.findFirst() // Optional<Info>
.map(info -> info.getMap().entrySet() // Set<Entry<String, Something>>
.stream() // Stream<Entry<String, Something>>
.filter(entry -> entry.getKey().equals("test"))
.map(Entry::getValue) // Stream<Something>
.collect(toList()) // List<Something>
) // Optional<List<Something>>
.orElse(Collections::emptyList) // List<Something>
If last line not specified then you'll be getting an Optional<List<Info>>
back.
EDIT: Lino's answer with limit
is more idiomatic, pick that one unless you really want to use Optional
in this way.
Assuming your code above is your complete business logic, you probably just to find the value of "test" in the first item in your list (thanks Lino for limit
). That'd be:
list.stream() // Stream<List<Info>>
.limit(1) // Stream<List<Info>> count 0/1
.flatMap(info::getMap) Stream<Map<String, Something>> 0/1
.map(map -> map.get("test")) Stream<Something> 0/1, possibly null
.filter(Objects::nonNull) Stream<Something> 0/1
.findFirst() Optional<Something>
For completeness, if you wanted to find ANY values of "test" in maps in your list, it'd be:
list.stream() // Stream<List<Info>>
.flatMap(info::getMap) Stream<Map<String, Something>>
.flatMap(map -> map.entrySet().stream()) // Stream<Entry<String, Something>>
.filter(entry -> entry.getKey().equals("test"))
.map(Entry::getValue) // Stream<Something>
.collect(toList()) // List<Something>
Upvotes: 1
Reputation: 393781
Assuming info.getMap
returns a java.util.Map
, I don't see why you need the inner stream pipeline at all.
Just use get("test")
to obtain the value of the "test"
key:
List result =
list.stream()
.map(info -> info.getMap().get("test"))
.filter(Objects::nonNull)
.limit(1)
.collect(Collectors.toList());
P.S., don't use a raw type. You should change the type of the returned list to List<ValueType>
where ValueType
is the type of values in the info.getMap()
Map
.
Upvotes: 3