用Java增加Map值的最有效方法
我希望这个问题不被视为这个论坛的基础,但我们会看到。 我想知道如何重构一些代码以获得更好的性能,而这些代码正在运行很多次。
假设我使用一个Map(可能是一个HashMap)创建一个词频列表,其中每个键都是一个字符串,并且该字符被计数,并且该值是一个整数,每当找到该单词的一个标记时该值就会递增。
在Perl中,递增这样一个值将非常简单:
$map{$word}++;
但在Java中,它更复杂。 这是我目前正在做的事情:
int count = map.containsKey(word) ? map.get(word) : 0;
map.put(word, count + 1);
这当然依赖于较新Java版本中的自动装箱功能。 我想知道你是否可以提出一种更有效的方式来增加这种价值。 是否有避免使用Collections框架和使用其他方法的良好性能原因?
更新:我已经做了几个答案的测试。 见下文。
一些测试结果
我已经得到了很多这个问题的好答案 - 谢谢大家 - 所以我决定运行一些测试并找出哪种方法实际上是最快的。 我测试的五种方法是:
方法
这就是我所做的...
结果
我将首先介绍结果以及下面的代码,以供有兴趣的人士参考。
正如所料, ContainsKey方法是最慢的,所以我会将每种方法的速度与该方法的速度进行比较。
结论
看来只有MutableInt方法和Trove方法明显更快,因为只有它们的性能提升超过10%。 但是,如果线程是一个问题,AtomicLong可能比其他人更有吸引力(我不太确定)。 我也用final
变量运行TestForNull,但差异可以忽略不计。
请注意,我没有在不同情况下分析内存使用情况。 我很乐意听到任何对MutableInt和Trove方法可能会影响内存使用情况的人有很好的见解。
就个人而言,我发现MutableInt方法最具吸引力,因为它不需要加载任何第三方类。 所以除非我发现问题,否则这就是我最可能去的方式。
代码
这是每种方法的关键代码。
的containsKey
import java.util.HashMap;
import java.util.Map;
...
Map<String, Integer> freq = new HashMap<String, Integer>();
...
int count = freq.containsKey(word) ? freq.get(word) : 0;
freq.put(word, count + 1);
TestForNull
import java.util.HashMap;
import java.util.Map;
...
Map<String, Integer> freq = new HashMap<String, Integer>();
...
Integer count = freq.get(word);
if (count == null) {
freq.put(word, 1);
}
else {
freq.put(word, count + 1);
}
的AtomicLong
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicLong;
...
final ConcurrentMap<String, AtomicLong> map =
new ConcurrentHashMap<String, AtomicLong>();
...
map.putIfAbsent(word, new AtomicLong(0));
map.get(word).incrementAndGet();
特罗韦
import gnu.trove.TObjectIntHashMap;
...
TObjectIntHashMap<String> freq = new TObjectIntHashMap<String>();
...
freq.adjustOrPutValue(word, 1, 1);
MutableInt
import java.util.HashMap;
import java.util.Map;
...
class MutableInt {
int value = 1; // note that we start at 1 since we're counting
public void increment () { ++value; }
public int get () { return value; }
}
...
Map<String, MutableInt> freq = new HashMap<String, MutableInt>();
...
MutableInt count = freq.get(word);
if (count == null) {
freq.put(word, new MutableInt());
}
else {
count.increment();
}
好的,可能是一个老问题,但Java 8有一个较短的方法:
Map.merge(key, 1, Integer::sum)
它做什么:如果密钥不存在,则将1作为值,否则将1与链接到密钥的值相加。 更多信息在这里
2016年的一点研究:https://github.com/leventov/java-word-count,基准源代码
每种方法的最佳结果(越小越好):
time, ms
kolobokeCompile 18.8
koloboke 19.8
trove 20.8
fastutil 22.7
mutableInt 24.3
atomicInteger 25.3
eclipse 26.9
hashMap 28.0
hppc 33.6
hppcRt 36.5
时间空间结果:
链接地址: http://www.djcxy.com/p/46353.html