这是对computeIfAbsent在这段代码中所做的事情的正确解释吗?

问题描述 投票:0回答:2

我正在阅读别人使用

computeIfAbsent
的代码。我不经常使用 lambda,并且在尝试了解它的用途时要保持谨慎。根据我自己的理解重写这个,这是正确的解释吗?

list.computeIfAbsent(info.getOwner(), k -> new CopyOnWriteArrayList<>()).add(info);
Object owner = info.getOwner();
     
if (list.get(owner) == null)
   list.put(owner, new CopyOnWriteArrayList<Info>(Arrays.asList(info)));

在这种情况下,我是否错过了不使用 lambda 方法的任何好处?文档中提到

computeIfAbsent()
是原子的,但是
add()
computeIfAbsent()
返回之后才会被调用。如果插入是原子的,
putIfAbsent()
不是更合适吗?

java lambda atomic
2个回答
0
投票

不,它们不一样。

第一个案例

  • 如果该值不存在,将创建
    ArrayList
    并将其添加到地图中。然后该列表将被返回并添加信息。
  • 如果该键存在值,则将返回现有列表并添加信息。

第二种情况

  • 仅当值为 null 时才会添加
    ArrayList
    。然后将添加新的 ArrayList 并将值添加到其中。
  • 但是不会添加后续值,因为
    map.get(owner)
    不会为 null 并且 map.put 将不会执行。

0
投票

是的,您错过了福利。

为什么不
putIfAbsent

使用

putIfAbsent
,如果该东西不存在,代码仍然会运行。您正在 still 创建一个新的 1 条目数组,其中包含
info
still 制作一个包装该列表的包装器列表,still 制作一个
CopyOnWriteArrayList
复制该包装列表,并传递对此的引用COWList 到
putIfAbsent
其中...

立即将其扔进垃圾桶。

为什么不直接做
if
的事情呢?

因为它不是原子的。当然,并非所有列表都是原子的,但第二个片段不可能是原子的。即使那个 list 引用(显然是一个 map,这对于地图来说是一个非常糟糕的名字!)是同步的,该代码也不起作用:另一个线程可能会在你的

.get 之间偷偷地输入一个值
电话和您的
put
电话。
那么这些 lambda 东西是什么?
第二个片段有点好,它涵盖了您想要做的事情,即:检查 

owner

是否已经在此地图中。如果它是

not

,那么我想创建一个新的 COWList 并将其作为值与

owner
相关联。但如果是的话,什么也不做。 但是,它并不是自动完成的。如果你自己不控制原子性过程,你就无法解决这个问题,例如与
synchronized
。这是[A]限制,因为任何尝试编写复杂的多核安全方法都不会起作用,因为每次尝试与地图交互时都需要重复(例如,像

ConcurrentMap

这样的东西是比这个东西复杂得多,而且 [B] 甚至还有相当多的代码。这个:

CopyOnWriteArrayList<Info> list;
synchronized {
  list = map.get(owner);
  if (list == null) {
    map.put(owner, list = new CopyOnWriteArrayList<Info>(Arrays.asList(info)));
  }
}
有很多东西要写。你每次都必须复制它。

你真正想做的是将一些东西交给map impl,以便它可以完成所有这些事情。但是,您需要给它一个配方:如果映射
本身

确定键当前未与某事物关联,因此是时候制作该事物并将其设置为与键关联的值,则您需要将其交给它制作该东西的食谱。

这就是 lambda。食谱。 就像你可以吃蛋糕,但你不能吃蛋糕食谱一样,lambda 与其制作的东西不同。

就像您可以将菜谱烹饪 0 次、1 次或 100 次一样,您可以根据需要多次调用 lambda。其中包括“从不”——如果密钥不存在,

computeIfAbsent

代码将会执行此操作。

就像菜谱一样,很容易复制(您可以将 lambda 传递给周围,它们的“制作”成本很便宜,就像复制菜谱比复制蛋糕要简单得多)。

就像菜谱一样,它可以有参数。食谱通常只是说“拿起你的平底锅并加热”。它通常不包括如何一起制作烹饪锅的说明。相反,该食谱需要平底锅作为输入。没有平底锅吗?无法“调用”食谱。
    

© www.soinside.com 2019 - 2024. All rights reserved.