第一种,最直观的计数器
每次循环都去检查Map中是否包含Key,如果包含则将原值+1再保存,如果不存在,则直接保存1.这种方式是最简单直接的一种方式,但是并不是最有效的方式,其低效的原因:
1、如果已经存在某个key(a),containsKey()和get()方法会扫描Map两次
2、由于Integer是不可变对象,因此每次循环,都会创建一个新的对象放到Map中。
public void naiveCounter(String sArr[]) {
HashMap<String, Integer> counter = new HashMap<String, Integer>();
for (String a : sArr) {
if (counter.containsKey(a)) {
int oldValue = counter.get(a);
counter.put(a, oldValue + 1);
} else {
counter.put(a, 1);
}
}
}
第二种,比较好的计数器
自然可以想到创建一个可变的Integer对象,这样可以避免创建过多的Integer对象
class MutableInteger {
private int val;
public MutableInteger(int val) {
this.val = val;
}
public int get() {
return val;
}
public void set(int val) {
this.val = val;
}
public String toString() {
return Integer.toString(val);
}
}
public void betterCounter(String[] sArr) {
HashMap<String, MutableInteger> newCounter = new HashMap<String, MutableInteger>();
for (String a : sArr) {
if (newCounter.containsKey(a)) {
MutableInteger oldValue = newCounter.get(a);
oldValue.set(oldValue.get() + 1);
} else {
newCounter.put(a, new MutableInteger(1));
}
}
}
第三种,高效的计数器
已经解决了创建过多Integer对象的问题,但是扫描两次Map,其实在HashMap中,存在一个能够返回当前值的方法(HashMap.put(key,value)),在上面的基础上,我们可以通过对原来的引用进行更新,而不必扫描两次Map.
public void efficientCounter(String[] sArr) {
HashMap<String, MutableInteger> efficientCounter = new HashMap<String, MutableInteger>();
for (String a : sArr) {
MutableInteger initValue = new MutableInteger(1);
MutableInteger oldValue = efficientCounter.put(a, initValue);
//MutableInteger是可变的,此处只需判断之前是否为空,
// 如果非空,则更新MutableInteger的引用即可
if (oldValue != null) {
initValue.set(oldValue.get() + 1);
}
}
}