forEach loop Java 8 for Map entry set
I'm trying to convert old conventional for each loop till java7 to java8's for each loop for a map entry set but I'm getting an error. Here's the code I'm trying to convert:
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
}
Here's the changes I have done:
map.forEach( Map.Entry<String, String> entry -> {
System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
});
I tried doing this as well :
Map.Entry<String, String> entry;
map.forEach(entry -> {
System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
});
But still facing error. The error I'm getting for this is :
Lambda expression's signature does not match the signature of the functional interface method accept(String, String)
Solution 1:
Read the javadoc: Map<K, V>.forEach()
expects a BiConsumer<? super K,? super V>
as argument, and the signature of the BiConsumer<T, U>
abstract method is accept(T t, U u)
.
So you should pass it a lambda expression that takes two inputs as argument: the key and the value:
map.forEach((key, value) -> {
System.out.println("Key : " + key + " Value : " + value);
});
Your code would work if you called forEach() on the entry set of the map, not on the map itself:
map.entrySet().forEach(entry -> {
System.out.println("Key : " + entry.getKey() + " Value : " + entry.getValue());
});
Solution 2:
Maybe the best way to answer the questions like "which version is faster and which one shall I use?" is to look to the source code:
map.forEach() - from Map.java
default void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
for (Map.Entry<K, V> entry : entrySet()) {
K k;
V v;
try {
k = entry.getKey();
v = entry.getValue();
} catch(IllegalStateException ise) {
// this usually means the entry is no longer in the map.
throw new ConcurrentModificationException(ise);
}
action.accept(k, v);
}
}
javadoc
map.entrySet().forEach() - from Iterable.java
default void forEach(Consumer<? super T> action) {
Objects.requireNonNull(action);
for (T t : this) {
action.accept(t);
}
}
javadoc
This immediately reveals that map.forEach() is also using Map.Entry internally. So I would not expect any performance benefit in using map.forEach() over the map.entrySet().forEach(). So in your case the answer really depends on your personal taste :)
For the complete list of differences please refer to the provided javadoc links. Happy coding!