Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using a stream based on the content of Optional<Map>

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.

like image 403
Jan Galinski Avatar asked Jun 15 '17 12:06

Jan Galinski


People also ask

Can we use stream on optional?

The stream() method of java. util. Optional class in Java is used to get the sequential stream of the only value present in this Optional instance. If there is no value present in this Optional instance, then this method returns returns an empty Stream.

Can we use map with streams?

mapper is a stateless function which is applied to each element and the function returns the new stream. Example 1 : Stream map() function with operation of number * 3 on each element of stream. // given function to this stream.

Why streams are not applicable to maps?

Streams cannot directly be created from maps because a map is not a collection.


2 Answers

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)
like image 120
marstran Avatar answered Nov 06 '22 15:11

marstran


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.

like image 41
user_3380739 Avatar answered Nov 06 '22 14:11

user_3380739