Let's take a closer look at the for loop to see how we can write functionally :
List<WordComparable> l = new ArrayList<>(); for (Map.Entry<String, Integer> entry : map.entrySet()) l.add(new WordComparable(entry.getKey(), entry.getValue()));
If we read this code in plain English, we can say "for each record of my card, to convert it to WordComparable and add it to the list."
Now we can rephrase this sentence "for each record of my map, let it convert it to WordComparable , and when we completely convert it, let me make a list from it."
Using this sentence, we see that we need to create a function: one that takes a map entry and converts it to WordComparable . So let it build! Java 8 introduces a new type called Function , which has one important method: apply . This method takes one input, converts it, and returns one output.
Writing good old Java, since Function is an interface, we can implement it to write our conversion code:
public class EntryConverter implements Function<Map.Entry<String, Integer>, WordComparable> { public WordComparable apply(Map.Entry<String, Integer> entry) { return new WordComparable(entry.getKey(), entry.getValue()); } }
Now that we have this converter, we need to use it for all records. Java 8 also introduces the concept of Stream , that is, a sequence of elements (note that this sequence can be infinite). Using this sequence, we can finally write into the code what we said earlier, i.e. "For each entry, convert it to WordComparable ." We use the map method, the purpose of which is to apply the method to each element of the stream.
We have a method: EntryConverter , and we build Stream our records using the Stream method.
So, we get:
map.entrySet().stream().map(new EntryConverter());
The last part of the sentence remains: "make it a List ", i.e. collect all the items in a List . This is done using the collect method. This method takes a Collector as an argument, that is, an object that can reduce the flow in the final container. Java 8 comes with many ready-made collectors; one of which is Collectors.toList() .
Finally, we get:
map.entrySet().stream().map(new EntryConverter()).collect(Collectors.toList());
Now, if we remove the temporary EntryConverter class and make it anonymous, we get what your IDE offers:
List<WordComparable> l = map.entrySet() .stream() //make a Stream of our entries .map(new Function<Map.Entry<String, Integer>, WordComparable>() { @Override public WordComparable apply(Map.Entry<String, Integer> entry) { return new WordComparable(entry.getKey(), entry.getValue()); } }) //let convert each entry to a WordComparable .collect(Collectors.toList()); //and make a List out of it
Now writing all this code is a bit cumbersome, especially declaring an anonymous class. Java 8 comes to the rescue with the new operator -> . This operator allows you to create Function much more painlessly than before: the left side corresponds to the argument of the function, and the right side corresponds to the result. This is called a lambda expression.
In our case, we get:
entry -> new WordComparable(entry.getKey(), entry.getValue())
You can also write this lambda expression using the block body and the return statement:
entry -> { return new WordComparable(entry.getKey(), entry.getValue()); }
Notice how this corresponds to what we wrote earlier in EntryConverter .
This means that we can reorganize our code into:
List<WordComparable> l = map.entrySet() .stream() .map(entry -> new WordComparable(entry.getKey(), entry.getValue())) .collect(Collectors.toList());
which is more readable and is what your IDE offers.
You can find more about lambda expressions on the Oracle website .