2

I have the following data set with Key is String and value as List of values.

I wanted to call a method with key and each value of list as parameters to the method. Iterate for all the keys. I am able to do it with two forEach loops as shown in my example below. I would like know if we can write the same logic using streams and flatMap in Java 8 without forEach inner loop? thanks

Map<String,ArrayList<String>> xhashMap ;

if(xhashMap!=null)  {

 xhashMap.forEach((k,l)-> {

    if(k.equals("ax")){
           l.forEach(v->{
            method1(v,AA.class);
           }
     }
    if(k.equals("bx")){
           l.forEach(v->{
            method1(v,BB.class);
           }
     }

  });

}
6
  • Why do you want to use a Stream for this? It seems like a Stream implementation will be more confusing; especially as you're mapping to different class types. Commented Aug 4, 2017 at 17:18
  • i thought if we have large set of data streams would perform well in this case. But I am not sure. So just checking. You think I am doing correctly and it can not be done in streams. I don't have experience with streams API. Just started learning Commented Aug 4, 2017 at 17:20
  • 1
    Seeing as you're seeding your data from a Map that is already in memory, it's likely not going to be any better to use a Stream - what you have above is probably the better way. Commented Aug 4, 2017 at 17:24
  • Ok thanks for your input. Commented Aug 4, 2017 at 17:26
  • Why are you iterating over the map to find specific keys? map.getOrDefault("ax", emptyList()).forEach(v -> method1(v, AA.class)) or, if missing key is an exceptional condition, simply map.get("ax").forEach(...) Commented Aug 4, 2017 at 18:27

3 Answers 3

1

It doesn't matter whether you use a for loop, forEach or the Stream API. In all cases, you are iterating over a Map to compare each key against a certain value, which is perverting the concept of maps, to associate the key with a value and provide (usually far better that linear) lookup methods.

Further, you should use a Map<String, List<String>> instead, not referring to an implementation type like ArrayList, and not letting it be null in the first place, instead of having it to check for null later-on.

If you follow theses advice, your code becomes

Map<String, List<String>> xhashMap;
// always initialize the map to a non-null reference

xhashMap.getOrDefault("ax", Collections.emptyList())
        .forEach(v -> method1(v, AA.class));
xhashMap.getOrDefault("bx", Collections.emptyList())
        .forEach(v -> method1(v, BB.class));

If the map is, as the variable name suggests, a hash map, the two lookups will have O(1) time complexity, but even a TreeMap with O(log(n)) complexity will be better than iterating over the map and compare all keys.

As long as the action consists of a sole method invocation with different parameters, there is not much gain in trying to re-use common code, as the sharing code would be much more complicated.

Sign up to request clarification or add additional context in comments.

Comments

1

Yes, we can't write it with Stream API, but it's not much better.

Since you are performing side effects and not collecting results, Stream would essentially be:

xhashMap.entrySet()
  .stream()
  .forEach(e -> ...);

and unfortunately, contain same logic inside the forEach.

Actually, you can even skip Stream creation at this point because you can perform forEach without creating a Stream:

xhashMap.entrySet()
  .forEach(e -> ...);

2 Comments

Thanks @Grzegorz, I agree. we don't need stream now. Your statement .entryset().forEach(e->...) . again I have to check below based on key the second parameter will change in my case. for example in case of key "ax" it will be AA.class,. so that's why I have to check the key value explicitly.
@techi e is an Entry and it contains both Key and Value - essentially it's not really better than your solution
0

Sure it can be done with flatMap and closures

xHashMap.entrySet().stream()
                .flatMap(e -> e.getValue().stream()
                        .<Runnable>map(v -> () -> {
                            final String k = e.getKey();
                            if (k.equals("ax")) {
                                method1(v, AA.class);
                            }
                            if (k.equals("bx")) {
                                method1(v, BB.class);
                            }
                        })
                )
                .forEach(Runnable::run);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.