将值放入Java中的映射*不*更新现有值(如果存在)

Posted

技术标签:

【中文标题】将值放入Java中的映射*不*更新现有值(如果存在)【英文标题】:Put a value into the map in Java *without* updating existing value if exists 【发布时间】:2012-01-17 01:56:51 【问题描述】:

我想做以下功能:

if (!map.contains(key)) 
  map.put(key, val);

更新:假设它不是HashMap,所以地图被实现为某种树。

但是请注意,它的效率有点低,因为如果我们进入 if 我们实际上搜索了两次地图。我实际上想做这样的事情:

map.put_if_new_key(key, val);

知道如何用 Java 实现吗?

【问题讨论】:

【参考方案1】:

如果您希望在绝大多数时间插入新元素。

ValType temp = map.put(key, val);
if(temp != null)
    map.put(key, temp);

我认为总的来说这不是一个好主意,但如果您能够充分推理您的用例,则值得考虑。

再想一想,如果您可以使用特定的地图实现,而不仅仅是地图接口,您可以使用 NavigableMap 来做到这一点

Map sub = map.subMap(key, true, key, true);
if (!sub.contains(key)) 
  sub.put(key, val);

由于子树的大小为 0 或 1 个节点,因此无需重复工作。

【讨论】:

关于第一种方法的警告:有两种情况可以返回 null。缺少键,或者键存在并且与值 null 相关联。用这种方法你无法分辨它是什么。 与 contains(key) 相同,因为本质上它会检查该键是否为空,因此如果您将一个键设置为空,然后检查它是否存在,它将返回 false,所以真的没有办法告诉无论方法是否设置了密钥。 @D3_JMultiply 嗯,什么?这不是它的工作原理。 contains() 仅在您确实将它们的键(CAN 为空)添加到地图时才返回 true,否则 - 这就是它的记录方式,但如果您不相信文档,您可以查看实施.. 真的很直接。【参考方案2】:

如果您有ConcurrentMap<K, V>,则有方法putIfAbsent

如果指定的键尚未与值关联,则将其与给定值关联。这相当于

if (!map.containsKey(key))
    return map.put(key, value);
else
    return map.get(key);

除了动作是原子执行的。

但是Map<K, V> 上不存在此方法。

【讨论】:

+1 表示(在代码中)这种实现并不比 OP 提供的更有效 但是注意——如果OP担心地图的两次查找略有增加,同步成本会差很多。 @JohnVint:是的。但是如果他正在使用ConcurrentMap,大概是因为他需要同步。无论哪种方式都会很昂贵:putIfAbsentcontains 然后 put 在同步块中。我预计putIfAbsent 会稍微快一些。 @John Vint 更糟糕的是,你是指毫秒的 1/10 左右吗?【参考方案3】:

我不认为您提出的代码效率低下。查看 key 是否已经存在于 Map 中,那么它是一个单一的地图查找。即使在未找到密钥的情况下,也没有 2 次搜索。只有 1 次搜索和 1 次插入到地图中。

【讨论】:

Insert 正在沿着树向下搜索到与搜索完全相同的位置。 @Drakosha:树?什么树? Map 接口不保证键存储在树中 - 这是 some 实现的实现细节。您使用的是什么 Map 实现?从您的问题来看,它可能很容易成为HashMap,在这种情况下没有树并且键查找将非常快(平均而言)。 @MarkByers 谢谢,我更新了这个问题。如果不是HashMap 使用你的“低效”方法会损失几分之一毫秒,不幸的是,无论你使用什么类型的地图,任何添加实现的方式都不会比在外面检查慢,如所见几乎可以保证,他们用来检查密钥是否不存在的方法可能与您创建功能所用的方法相同。如果您制作了一个 Map,具有检查密钥是否存在的功能,然后您制作了一种更有效的方法来检查它以防止覆盖,您不会也将检查方法更新为更有效的方法吗?【参考方案4】:

我认为没有任何方法可以检查“contains()”以查看密钥是否存在。

查看此处,看看这是否适合您:

What happens when a duplicate key is put into a HashMap?

【讨论】:

以上是关于将值放入Java中的映射*不*更新现有值(如果存在)的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Java Spring Boot 在不插入新值的情况下更新表中的现有值

如何更新字段以将值添加到现有值?

ETL工具kettle基础--插入更新组件

php 在数组中的特定键后插入值或键/值对。如果key不存在,则将值附加到数组的末尾。

php 在数组中的特定键后插入值或键/值对。如果key不存在,则将值附加到数组的末尾。

存储现有值时,Java的HashMap密钥替换