I have a Map
with Optional
values.
I want to filter it to remove empty values.
Map<K, Optional<T>> input;
Map<K, T> result = input.
// here is some code I'm looking for
.collect(Collector.toMap(???));
What is easiest way to achieve it?
All I can think of requires Optional.get
and I don’t like that IDE warns me about it.
2
The easiest way to do it, especially while avoiding Optional.get()
, isn’t going to involve streams at all; more like
Map<K, T> result = new LinkedHashMap<>();
input.forEach((k, vOpt) -> {
vOpt.ifPresent(v -> result.put(k, v));
});
(In general, if there isn’t a really obvious way to do something with streams, it’s generally going to be simpler and cleaner not to use streams at all.)
If you insist on using a Collector
, it’s possible but requires a carefully customized one, especially if you won’t tolerate Optional.get()
.
map.entrySet().stream()
.collect(Collector.of(
LinkedHashMap::new,
(map, entry) -> entry.getValue().ifPresent(v -> map.put(entry.getKey(), v)),
(m1, m2) -> {
m1.putAll(m2);
return m1;
}));
If you can tolerate Optional.get()
, you might consider it simpler to write
map.entrySet().stream()
.filter(e -> e.getValue().isPresent())
.collect(Collectors.toMap(Entry::getKey, e -> e.getValue().get()));
One way is by using Stream.mapMulti
(available since Java 16):
Map<K, T> result = input.entrySet()
.stream()
.<Map.Entry<K, T>> mapMulti((x, c) -> {
if (x.getValue().isPresent()) {
c.accept(Map.entry(x.getKey(), x.getValue().get()));
}
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
This allows an imperative approach.
Here’s a more functionalish way that does exactly the same:
Map<K, T> result = input.entrySet()
.stream()
.<Map.Entry<K, T>> mapMulti((x, c) -> x.getValue()
.ifPresent(v -> c.accept(Map.entry(x.getKey(), v))))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
The code above uses Optional.ifPresent
.
Another way is by using Collectors.filtering
:
Map<K, T> result = input.entrySet()
.stream()
.collect(Collectors.filtering(
x -> x.getValue().isPresent(),
Collectors.toMap(Map.Entry::getKey, x -> x.getValue().get())));
(Note: my IntelliJ produces a warning on Optional.get()
, but this warning is wrong).