在编程中,经常会用到HashMap作为计数器,本文简单介绍三种实现方式

第一种,最直观的计数器。

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);
}
}
}

在这种方式中,每次循环都去检查Map中是否包含Key,如果包含则将原值+1再保存,如果不存在,则直接保存1.这种方式是最简单直接的一种方式,但是并不是最有效的方式,其低效的原因:

1、如果已经存在某个key(a),containsKey()和get()方法会扫描Map两次

2、由于Integer是不可变对象,因此每次循环,都会创建一个新的对象放到Map中。

第二种,比较好的计数器

由于上述原因,自然可以想到创建一个可变的Integer对象,这样可以避免创建过多的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);
}
}
}

下面是经过500W次操作后,三者方法所消耗的时间

start test naiveCounter
end test naiveCounter,time is:5629

start test betterCounter
end test betterCounter,time is:5030

start test efficientCounter
end test efficientCounter,time is:4418

可以看出,最后一种确实是三种里面最高效的方式

在java中高效的计数器的更多相关文章

  1. 在 Java 中高效使用锁的技巧--转载

    竞争锁是造成多线程应用程序性能瓶颈的主要原因 区分竞争锁和非竞争锁对性能的影响非常重要.如果一个锁自始至终只被一个线程使用,那么 JVM 有能力优化它带来的绝大部分损耗.如果一个锁被多个线程使用过,但 ...

  2. 七、如何在Java中高效检查一个数组是否含有一个值

    如何检查一个数组(非排序的)是否包含特定的值.这是个非常有用或经常被在Java中使用.这是个在Stack Overflow中高得票的问题.在已经高得票的答案中,有许多不同的处理方法,但是时间的复杂度非 ...

  3. 161101、在Java中如何高效判断数组中是否包含某个元素

    如何检查一个数组(无序)是否包含一个特定的值?这是一个在Java中经常用到的并且非常有用的操作.同时,这个问题在Stack Overflow中也是一个非常热门的问题.在投票比较高的几个答案中给出了几种 ...

  4. 在Java中如何高效的判断数组中是否包含某个元素

    原文出处: hollischuang(@Hollis_Chuang) 如何检查一个数组(无序)是否包含一个特定的值?这是一个在Java中经常用到的并且非常有用的操作.同时,这个问题在Stack Ove ...

  5. 在Java中怎样高效的推断数组中是否包括某个元素

    来自 http://www.hollischuang.com/archives/1269? 怎样检查一个数组(无序)是否包括一个特定的值?这是一个在Java中经经常使用到的并且非常实用的操作.同一时候 ...

  6. 在java中构建高效的结果缓存

    文章目录 使用HashMap 使用ConcurrentHashMap FutureTask 在java中构建高效的结果缓存 缓存是现代应用服务器中非常常用的组件.除了第三方缓存以外,我们通常也需要在j ...

  7. 在Java中如何高效判断数组中是否包含某个元素

    如何检查一个数组(无序)是否包含一个特定的值?这是一个在Java中经常用到的并且非常有用的操作.同时,这个问题在Stack Overflow中也是一个非常热门的问题.在投票比较高的几个答案中给出了几种 ...

  8. Java中的GC操作及相关概念

    一.GC Roots Tracing的基本思路:通过一系列名为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所经过的路径称为引用链(Reference Chai ...

  9. 面试中关于Java中涉及到知识点(转)

    本篇文章会对面试中常遇到的Java技术点进行全面深入的总结,帮助我们在面试中更加得心应手,不参加面试的同学也能够借此机会梳理一下自己的知识体系,进行查漏补缺. 1. Java中的原始数据类型都有哪些, ...

随机推荐

  1. H5动画优化之路

    H5动画60fps之路 在移动端,和Native相比,H5一直都被人吐槽性能差,尤其是在动画方面. 谈到整个Web app的生命周期,一般分为四个部分: 加载 等待用户 响应用户 动画 一般情况下,首 ...

  2. zoj 3761

    很简单但很虐心的一道题: 我感觉自己的算法没错,但是老是过不了:= = 但是还是把代码贴出来: 我的方法,用并查集的方式做一课树,然后对树进行遍历: 有多少棵树就有多少个点剩余: #include&l ...

  3. Ubuntu添加PPA源

    转自Ubuntu添加PPA源 什么是PPA PPA,表示Personal Package Archives,也就是个人软件包集 很多软件包由于各种原因吧,不能进入官方的Ubuntu软件仓库.为了方便U ...

  4. PHP basename() 函数

    定义和用法 basename() 函数返回路径中的文件名部分. 语法 basename(path,suffix) 参数 描述 path 必需.规定要检查的路径. suffix 可选.规定文件扩展名.如 ...

  5. MongoDB实战指南(四):MongoDB的Journaling日志功能

    mongoDB的Journaling日志功能与常见的log日志是不一样的,mongoDB也有log日志,它只是简单记录了数据库在服务器上的启动信息.慢查询记录.数据库异常信息.客户端与数据库服务器连接 ...

  6. [线段树]HDOJ5091 Beam Cannon

    题意:给n, w, h  (1 <= N <= 10000,1 <= W <= 40000,1 <= H <= 40000) $w\times h$是可以射到的范围 ...

  7. mjpg-streamer on raspberrypi

    http://sourceforge.net/projects/mjpg-streamer/ svn address svn checkout svn://svn.code.sf.net/p/mjpg ...

  8. Android USB Host 通信程序

    换到了一家新公司,于是就有了新的项目.这次的项目 要用Android SDK与USB HID设备进行通信.第一次接触Android SDK,以及USB,记录下源程序.开发过程以及一些心得. 首先,要感 ...

  9. 中国版dropbox“坚果云”和它背后的团队故事(大的优势就在于他为用户提供了设定多个文件夹的权利)

    (速途网专栏 作者:娄昊川)坚果云是一款中文存储服务,前身是“坚果铺子”,提供免费的云空间,与dropbox类似,用户可以直接把档案同步到坚果云,供自己和伙伴用任何设备访问.自上线以来,几乎所有用户都 ...

  10. [Android] 修改设备访问权限

    在硬件抽象层模块中,我们是调用open函数来打开对应的设备文件的.例如,在2.3.2小节中开发的硬件抽象层模块freg中,函数freg_device_open调用open函数来打开设备文件/dev/f ...