HashMap计数器的高效实现

原始的计数器

在实际应用中,我们经常把HashMap作为一个计数器使用.例如统计一篇文章中单词 'the' 出现了多少次.于是我们很轻松地就能写出下面的程序:
Map<String, Integer> counter = new HashMap<String, Integer>();
		for(String s : strs) {
			if(counter.containsKey(s)) {
				Integer times = counter.get(s);
				times = times + 1;
			} else {
				counter.put(s, 1);
			}
		}

这个计数器确实可以完成我们所需的功能,但在速度上却慢了点.仔细分析不难发现,由于Integer是immutable的,即不可变的,所以在执行times = times + 1这行代码时实际上会创建一个新的Integer对象,然后再赋给times.这样一来,每次将次数 +1 时都会创建一个Integer,等循环执行完内存中可能会存在成千上万个垃圾Integer对象.所以,如果能将不可变的Integer改成可变的(mutable),能提高程序性能.

改进后的计数器

我们可以自己定义一个名为MutableInteger 的类来实现可变:
class MutableInteger {
	int value;
	
	public MutableInteger(int val) {
		this.value = val;
	}

	public int getValue() {
		return value;
	}

	public void setValue(int value) {
		this.value = value;
	}
}

改进后的程序代码如下:
Map<String, MutableInteger> counter = new HashMap<String, MutableInteger>();
		for(String s : strs) {
			if(counter.containsKey(s)) {
				MutableInteger times = counter.get(s);
				times.setValue(times.getValue() + 1); // 不会每次都创建新对象了
			} else {
				counter.put(s, new MutableInteger(1));
			}
		}

做完这步工作以后,再进行分析,也不难发现,在第一个if分支中,HashMap实际上会被查找2次.即,containsKey()会做一次查找,put()又会进行一次查找.显然这样也会降低程序性能.我们可以进一步优化程序,使其只进行一次查找就能完成所有的操作.

高效的计数器

代码如下:
Map<String, MutableInteger> counter = new HashMap<String, MutableInteger>();
		for(String s : strs) {
			MutableInteger newValue = new MutableInteger(1);
			MutableInteger oldValue = counter.put(s, newValue);
			
			if(null != oldValue) {
				newValue.setValue(oldValue.getValue() + 1);
			}
		}

这段代码看进来好像有些不好理解,我们来分析一下:
1. 执行
MutableInteger newValue = new MutableInteger(1);
时,会创建一个新的MutableInteger对象,初始化为1.
2. 执行
MutableInteger oldValue = counter.put(s, newValue);
时,程序会将刚刚创建的newValue放到HashMap中,同时返回执行完put()方法之后当前的健所对应的值.
3. 如果oldValue为不为空,则说明原来的HashMap中没有这个键.而此时我们已经将没有的键put进去了,且其对应的值恰好是newValue所引用的对象.因此我们只需要通过newValue调用setValue()方法就能修改到值了.

我编写了一个测试程序,对这3个counter进行了性能对比,结果如下:


大概是8 : 7 : 6.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值