我希望这个问题对于这个论坛来说不算太基础,但我们会看到。我想知道如何重构一些代码以获得更好的性能,这些代码运行了很多次。
假设我正在使用Map(可能是HashMap)创建一个单词频率列表,其中每个键都是一个字符串,其中包含要计数的单词,并且值是一个Integer,每次找到单词的标记时它都会递增。
在Perl中,增加这样的值将非常简单:
$map{$word}++;
但在Java中,它要复杂得多。这是我目前正在做的方式:
int count = map.containsKey(word) ? map.get(word) : 0;
map.put(word, count + 1);
当然,这取决于较新Java版本中的自动装箱功能。我想知道你是否可以建议一种更有效的方法来增加这样的价值。是否有良好的性能原因可以避开Collections框架并使用其他东西?
发布于 2018-10-16 13:58:33
查看Google Collections Library这样的事情总是一个好主意。在这种情况下,Multiset可以解决这个问题:
Multiset bag = Multisets.newHashMultiset();
String word = "foo";
bag.add(word);
bag.add(word);
System.out.println(bag.count(word)); // Prints 2
有类似Map的方法来迭代键/条目等。在内部,实现当前使用a HashMap<E, AtomicInteger>
,所以你不会招致拳击费用。
发布于 2018-10-16 14:49:04
我已经为这个问题得到了很多好的答案 - 谢谢大家 - 所以我决定运行一些测试并找出哪种方法实际上最快。我测试的五种方法是:
这就是我做的......
我将首先介绍结果,并为感兴趣的人提供下面的代码。
该的containsKey方法是,如预期,最慢的,所以我给每个方法的速度相比,该方法的速度。
似乎只有MutableInt方法和Trove方法明显更快,因为只有它们的性能提升超过10%。但是,如果线程是一个问题,AtomicLong可能比其他人更有吸引力(我不太确定)。我还使用final
变量运行TestForNull ,但差异可以忽略不计。
请注意,我没有在不同的方案中分析内存使用情况。我很高兴听到任何人对MutableInt和Trove方法如何影响内存使用情况有很好的见解。
就个人而言,我发现MutableInt方法最具吸引力,因为它不需要加载任何第三方类。所以,除非我发现它的问题,这是我最有可能的方式。
以下是每种方法的关键代码。
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);
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);
}
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);
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();
}
https://stackoverflow.com/questions/-100002914
复制相似问题