In Java 8 ConcurrentHashMap
had two new methods introduced viz. forEach
and forEachEntry
.
On closer look both of them have essentially same arguments - forEach
has key & value supplied via BiConsumer
while forEachEntry
has Map.Entry
supplied via Consumer
from where key & value can be derived.
A simple use case to print all the map entries can be implemented by either of them as below
ConcurrentHashMap<String, Integer> map = Stream.of("One", "Two", "Three", "Four", "Five").
collect(Collectors.toConcurrentMap( str -> str,
str -> str.length(),
(str, len) -> len,
ConcurrentHashMap::new));
map.forEach(1, (k, v) -> System.out.println(k + " " + v));
map.forEachEntry(1, entry -> System.out.println(entry.getKey() + " " + entry.getValue()));
Moreover from docs the Map.Entry.setValue
isn't supported for bulk operation; so the benefit of having the Map.Entry
over plain key-value seems defeated.
.... that may transiently change while computation is in progress; and except for forEach actions, should ideally be side-effect-free. Bulk operations on
Map.Entry
objects do not support methodsetValue
.
Thus IMO two methods can be used interchangeably (unless I miss something very obvious)
So my questions are
Only difference is that one accepts a BiConsumer and the other just a Consumer.
Here the relevant code:
// forEach
static final class ForEachMappingTask<K,V>
extends BulkTask<K,V,Void> {
final BiConsumer<? super K, ? super V> action;
ForEachMappingTask
(BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
BiConsumer<? super K,? super V> action) {
super(p, b, i, f, t);
this.action = action;
}
public final void compute() {
final BiConsumer<? super K, ? super V> action;
if ((action = this.action) != null) {
for (int i = baseIndex, f, h; batch > 0 &&
(h = ((f = baseLimit) + i) >>> 1) > i;) {
addToPendingCount(1);
new ForEachMappingTask<K,V>
(this, batch >>>= 1, baseLimit = h, f, tab,
action).fork();
}
for (Node<K,V> p; (p = advance()) != null; )
action.accept(p.key, p.val);
propagateCompletion();
}
}
}
// forEachEntry
static final class ForEachEntryTask<K,V>
extends BulkTask<K,V,Void> {
final Consumer<? super Entry<K,V>> action;
ForEachEntryTask
(BulkTask<K,V,?> p, int b, int i, int f, Node<K,V>[] t,
Consumer<? super Entry<K,V>> action) {
super(p, b, i, f, t);
this.action = action;
}
public final void compute() {
final Consumer<? super Entry<K,V>> action;
if ((action = this.action) != null) {
for (int i = baseIndex, f, h; batch > 0 &&
(h = ((f = baseLimit) + i) >>> 1) > i;) {
addToPendingCount(1);
new ForEachEntryTask<K,V>
(this, batch >>>= 1, baseLimit = h, f, tab,
action).fork();
}
for (Node<K,V> p; (p = advance()) != null; )
action.accept(p);
propagateCompletion();
}
}
}
Somehow like the two methods to set size of Component: setSize(Dimension)
and setSize(int, int)
I believe it was just a matter of convenience I for instance prefer to have the key an the value already in the parameters intead of having to call getKey()/getValue() all the time. In fact I don't even use/care with forEach functions, once you become more seasoned in functional programming you will learn this kind of function is by far the least useful of FP, so much that purely functional languages like Haskell doesn't even have them. Everything you expect to do with forEach you can do with map/reduce/collect with the added benefit of no side-effects.
BtW: Posting the link to the Javadoc for convenience. https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With