HashMap<String,Integer>
。如何更新(递增)我找到的每个字符串键的整数值?
一种方法是删除并重新输入该对,但开销会成为一个问题。另一种方法是只放置新的一对,旧的将被替换。
在后一种情况下,如果我正在尝试插入一个新键时发生哈希码冲突会发生什么? 哈希表的正确行为应该是为其分配不同的位置,或者将其制作成当前桶中的列表。
map.put(key, map.get(key) + 1);
应该没问题。它将更新现有映射的值。请注意,这使用了自动装箱。通过使用map.get(key)
,我们可以获取相应键的值,然后您可以根据需求进行更新。这里我更新为将值增加1。
您可以使用computeIfPresent
方法,并提供一个映射函数,该函数将基于现有值计算出一个新值。
例如,
Map<String, Integer> words = new HashMap<>();
words.put("hello", 3);
words.put("world", 4);
words.computeIfPresent("hello", (k, v) -> v + 1);
System.out.println(words.get("hello"));
另外,您可以使用merge
方法,其中1是默认值,并且该函数将现有值增加1:
words.merge("hello", 1, Integer::sum);
此外,还有一系列其他有用的方法,比如putIfAbsent
、getOrDefault
、forEach
等。
words.put("hello", null);
)时不会一致地工作,结果仍然是null
而不是我期望的1
。 - Tao Zhangcompute()
方法来替代,它也可以处理 null
值。 - Konstantin Milyutin.merge
是我的解决方案,使用Integer::sum
。 - S_KJava 8的简化写法:
map.put(key, map.getOrDefault(key, 0) + 1);
这里使用了HashMap的方法来通过键(key)检索值(value),但是如果无法检索到键,则返回指定的默认值(在本例中为“0”)。
这种方法在Java核心中得到支持:HashMap<K,V> getOrDefault(Object key, V defaultValue)
hashmap.put(key, hashmap.get(key) + 1);
方法put
会替换现有键的值,如果该键不存在,则会创建该键。
null + 1
,因为这会尝试将 null
拆箱成整数来执行增量。 - AxelH用AtomicInteger
替换Integer
,并调用其中之一的incrementAndGet
/getAndIncrement
方法。
另一种方法是将int
封装在您自己的MutableInteger
类中,该类具有increment()
方法,但您仍需要解决线程安全问题。
MutableInteger
更好,因为AtomicInteger
使用了有开销的volatile
。我会使用int [1]
而不是MutableInteger
。 - Oliv一行代码解决方案:
map.put(key, map.containsKey(key) ? map.get(key) + 1 : 1);
@Matthew的解决方案是最简单的,在大多数情况下表现良好。
如果您需要高性能,AtomicInteger是一个更好的解决方案,就像@BalusC所说。
然而,如果线程安全不是问题,更快的解决方案是使用TObjectIntHashMap,它提供了一个increment(key)方法,并且使用原始类型和比创建AtomicIntegers更少的对象。例如:
TObjectIntHashMap<String> map = new TObjectIntHashMap<String>()
map.increment("aaa");
您可以按照以下方式增加,但您需要检查其是否存在,以避免抛出NullPointerException异常
if(!map.containsKey(key)) {
p.put(key,1);
}
else {
p.put(key, map.getKey()+1);
}
可能有点晚了,但这是我的意见。
如果您使用的是Java 8,则可以利用computeIfPresent方法。如果指定键的值存在且非空,则尝试计算给定键及其当前映射值的新映射。
final Map<String,Integer> map1 = new HashMap<>();
map1.put("A",0);
map1.put("B",0);
map1.computeIfPresent("B",(k,v)->v+1); //[A=0, B=1]
ConcurrentHashMap
和AtomicInteger。从文档中得知:final Map<String,AtomicInteger> map2 = new ConcurrentHashMap<>();
map2.putIfAbsent("A",new AtomicInteger(0));
map2.putIfAbsent("B",new AtomicInteger(0)); //[A=0, B=0]
map2.get("B").incrementAndGet(); //[A=0, B=1]
需要注意的一点是,我们正在调用 get
方法来获取键为B
的值,然后在其值上调用 incrementAndGet()
方法,而它的值当然是 AtomicInteger
类型。我们可以进行优化,因为 putIfAbsent
方法会返回该键的值(如果已经存在):
map2.putIfAbsent("B",new AtomicInteger(0)).incrementAndGet();//[A=0, B=2]
顺便提一句,如果我们计划使用AtomicLong,那么根据文档,在高并发情况下,LongAdder的预期吞吐量显着更高,但空间消耗更大。此外,请查看这个问题。
if (hashmap.containsKey(key)) {
hashmap.put(key, hashmap.get(key)+1);
} else {
hashmap.put(key,1);
}
getOrDefault
避免这种情况,例如:map.put(key, count.getOrDefault(key, 0) + 1);
。 - Martin