techi
techi

Reputation: 133

How to iterate HashMap of ArrayList in Java 8 with streams

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);
           }
     }

  });

}

Upvotes: 2

Views: 8797

Answers (3)

user8454548
user8454548

Reputation:

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);

Upvotes: 0

Holger
Holger

Reputation: 298559

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.

Upvotes: 1

Grzegorz Piwowarek
Grzegorz Piwowarek

Reputation: 13873

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 -> ...);

Upvotes: 1

Related Questions