ConcurrentHashMap中forEach和forEachEntry有什么区别

时间:2017-03-15 12:49:50

标签: java java-8

在Java 8 ConcurrentHashMap中引入了两个新方法即。 forEachforEachEntry

仔细看看它们两个都有相同的论点 - forEach有关键&amp;当BiConsumer forEachEntry Map.Entry通过Consumer提供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())); 时提供的价值来自密钥&amp;价值可以得出。

打印所有地图条目的简单用例可以通过以下任一方式实现,如下所示

Map.Entry.setValue

此外,从文档中Map.Entry不支持批量操作;因此,使Map.Entry超过普通键值的好处似乎被打败了。

  

....在计算过程中可能会暂时改变;除了forEach动作外,理想情况下应该是无副作用的。对setValue个对象的批量操作执行 支持方法array:3 [▼ 0 => array:2 [▼ "x" => "Kasaa" "y" => "8" ] 1 => array:2 [▼ "x" => "Pasa" "y" => "9" ] 2 => array:2 [▼ "x" => "tasa" "y" => "8" ] ]

因此,IMO两种方法可以互换使用(除非我错过了一些非常明显的

所以我的问题是

  • 为什么要引入两种基本相同签名的方法
  • 如果有什么不同之处
  • 一种方法比另一种方法有什么好处(一个解释它们的简单用例就足够了

3 个答案:

答案 0 :(得分:4)

唯一不同的是,一个接受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)

答案 1 :(得分:4)

我认为这只是一个方便的问题,例如我更喜欢让密钥成为必须始终调用getKey()/ getValue()的参数intead中的值。实际上我甚至没有使用/关注forEach函数,一旦你在函数式编程中变得更加老练,你就会知道这种函数是迄今为止最不实用的FP,所以像Haskell这样的纯函数语言甚至都没有拥有他们。你期望用forEach做的一切,你可以做map / reduce / collect,没有任何副作用。

BtW:为方便起见,发布了指向Javadoc的链接。 https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ConcurrentHashMap.html

答案 2 :(得分:0)

显然没有功能差异。它只是一个多元化的API,让开发人员感到舒适。通常,您为操作使用(k,v)参数,但有时,您可能正在操纵条目实例并将其推送到其他消耗条目的其他API&lt;&gt;对象。 不幸的是,我无法弄清楚任何一个例子,但由于Entry是地图的内部类,它也可以访问地图的某些成员,条目存储在。