Extract Multiline Lambda Expression while using ForEach while iterating a Map in Java 8

Viewed 675

I am iterating a map like below using Java 8 with forEach

Map<Integer,String> testMap = new HashMap<>();
testMap.put(1, "Atul");
testMap.put(2, "Sudeep");
testMap.put(3, "Mayur");
testMap.put(4, "Suso");

testMap.entrySet().forEach( (K)-> {         
                System.out.println("Key ="+K.getKey()+" Value = "+K.getValue());
                System.out.println("Some more processing ....");            
            }

    );

My question is :

1) How do we extract a method out of forEach while processing in a map?

2)That is, the portion of code inside forEach should be wrapped inside method:

        System.out.println("Key ="+K.getKey()+" Value = "+K.getValue());
        System.out.println("Some more processing ....");    

3) I understand the forEach method in this case expects a Consumer Functional Interface` which has below signature -

void accept(T t); 

4) So what I want is something like this :

   //declare a consumer object 
   Consumer<Map.Entry<Integer,String>> processMap = null;

  // and pass it to ForEach 
  testMap.entrySet().forEach(processMap);

5) Can we achieve this?

3 Answers

I understand the forEach method in this case expects a Consumer Functional Interface` which has below signature

forEach() expects indeed a Consumer but to process a Consumer you don't need necessarily a Consumer. What you need is a method that respects the input/output of the Consumer functional interface, that is Entry<Integer,String> input / void output.

So you could just invoke a method that has as parameter the Entry :

testMap.entrySet().forEach(k-> useEntry(k)));

or

testMap.entrySet().forEach(this::useEntry));

with useEntry() such as :

private void useEntry(Map.Entry<Integer,String> e)){        
    System.out.println("Key ="+e.getKey()+" Value = "+e.getValue());
    System.out.println("Some more processing ....");                        
}

Declaring a Consumer<Map.Entry<Integer,String>> that you pass to forEach() such as :

Consumer<Map.Entry<Integer,String>> consumer = this::useEntry;
//...used then :
testMap.entrySet().forEach(consumer);

makes sense only if the consumer in your forEach() is designed to be variabilized in a some way (computed/passed by the client or anyway).
If you are not in this case and that you use a Consumer, you finally made things more abstract and complicated than it is effectively required.

What about

public void processMap(Map.Entry K){
  System.out.println("Key ="+K.getKey()+" Value = "+K.getValue());
  System.out.println("Some more processing ....");
}

and then use it like:

testMap.entrySet().forEach((K)-> processMap(K));

You can use a method reference:

Consumer<Map.Entry<Integer,String>> processMap = SomeClass::someMethod;

Where the method is defined as:

public class SomeClass {

    public static void someMethod (Map.Entry<Integer,String> entry) {
        System.out.println("Key ="+entry.getKey()+" Value = "+entry.getValue());
        System.out.println("Some more processing ....");
    }

}

You can even make the method more generic, if you wish:

public static <K,V> void someMethod (Map.Entry<K,V> entry) {
    System.out.println("Key ="+entry.getKey()+" Value = "+entry.getValue());
    System.out.println("Some more processing ....");
}
Related