What is the difference between forEach and forEachEntry in ConcurrentHashMap

Java 8 ConcurrentHashMapintroduced two new methods: forEachand forEachEntry.

On closer inspection, both of them have essentially the same arguments. forEachhas a key and value provided through BiConsumer, and forEachEntryhas Map.Entry, supplied with Consumer, from which a key and value can be obtained.

A simple option for printing all map entries can be implemented by any of them, as shown 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()));

In addition, the documents are Map.Entry.setValuenot supported for bulk operations; therefore, the advantage of having Map.Entryover the normal key value seems defeated.

.... , ; , . Map.Entry setValue.

, ( - )

,

  • - ,
  • ( , )
+4
3

, BiConsumer, - .

:

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

- : setSize(Dimension) setSize(int, int)

+4

, , , , , , getKey()/getValue(). / forEach, , , , , FP, , , Haskell, . , forEach, // .

BtW: Javadoc . https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html

+4

Obviously, there is no functional difference. This is just an extended API for the convenience of developers. Typically, you use the (k, v) parameters for your actions, but sometimes you can manipulate input instances and push them to some other Entry <> resources using the API. Unfortunately, I cannot find a single example, but since Entry is an internal class of the map, it can also access some members of the map, the record is saved.

0
source

Source: https://habr.com/ru/post/1672354/


All Articles