问题
I get a map from a service not under my control that might be null and want to process it, let's say, filter, map and reduce to a single element I need.
Question: is there a "link" from Optional to Stream?
I tried (among other things):
return Optional.ofNullable(getMap())
.map(Map::entrySet) // gets the entryset
.map(Stream::of)
.orElseGet(Stream::empty)
// i would then like to continue with
.filter(e -> e.getKey().startsWith("f")
.map(Entry::getValue)
.findFirst();
but then I get not Stream<Entry>
but Stream<Set<Entry>>
... is there a way to somehow flatMap a collection or map out of an Optional?
Note: I am interested in a fluent, pure stream/optional approach here. It works of course when I save the map to local var first and make sure it is not null.
回答1:
Your mistake is in this line:
.map(Stream::of)
The of
function takes a single parameter (or a vararg parameter), and returns a stream with only that element. You will therefore get a Stream<Set<Map.Entry>>
. Instead, you should call the stream method on the entryset, like this:
.map(Set::stream)
回答2:
I think I'm going to answer the question.
return Optional.ofNullable(getMap())
.map(Map::entrySet) // gets the entryset
.map(Stream::of)
.orElseGet(Stream::empty)
// i would then like to continue with
.filter(e -> e.getKey().startsWith("f")
.map(Entry::getValue)
.findFirst();
I'm sick, really sick when I saw above code. Is it really so important for you write code in fluent approach, instead of writing simple code? first of all, as @ Didier L mentioned in the comments, it's wrong way to use Optional
. Secondly, the code is so hard to read, isn't it? if you write it with defining a local variable:
Map<String, Integer> map = getMap();
return map == null ? Optional.<Integer> empty()
: map.entrySet().stream()
.filter(e -> e.getKey().startsWith("f")).map(Entry::getValue).findFirst();
Isn't it much clear? Or you can do it with StreamEx if you can't get over not using fluent approach:
StreamEx.ofNullable(getMap())
.flatMapToEntry(Function.identity())
.filterKeys(k -> k.startsWith("f")).values().findFirst();
Or my library AbacusUtil
EntryStream.of(getMap()).filterByKey(k -> k.startsWith("f")).values().first();
Always trying to look for a better approach if things are stuck.
来源:https://stackoverflow.com/questions/44567806/using-a-stream-based-on-the-content-of-optionalmap