这个问题可能被认为太基础了,但是在论坛上经常被问到。 在本文中,我将讨论一种仅在Map ONCE中搜索键的方法。

让我们首先来看一个例子。 假设我正在使用Map创建一个字符串频率列表,其中每个键是一个正在计数的String ,值是一个Integer ,每次添加一个String都会递增。 实现它的一种直接方法是

int count = map.containsKey(string) ? map.get(string) : 0;
map.put(string, count + 1);

这段代码运行很慢,因为它在地图上包含三个潜在的昂贵操作,即containsKey()get()[put()](http://docs.oracle.com/javase/7/docs/ api / java / util / Map.html#put(K,V)) 。 每个都需要在地图中搜索关键字。 现在,让我们重构代码以获得更好的性能。

整数与MutableInteger与AtomicInteger

我们必须调用三个昂贵的操作的重要原因之一是使用Integer进行计数。 在Java中, Integer不可变的 。 它阻止我们在构造后修改整数值。 因此,要增加一个计数器,我们必须首先从映射中获取整数,然后通过添加一个整数来创建另一个新整数,然后将其放回映射中。

为了使计数器可变,有几种方法。 一种是简单地创建自己的MutableInteger ,就像我在下面显示的那样。

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

另一种方法可能是在Java中使用AtomicInteger ,该方法用于原子增量计数器等应用程序中。 但是AtomicInteger的主要选择是如果您希望通过对整数进行操作来实现线程安全。 因此,它不能用作Integer的替代。 基于此,如果您的项目不是线程安全性的重要考虑因素,则我不建议您使用AtomicInteger

仅搜索一次密钥

使用MutableInteger之后 ,我们可以将上面的代码更改为

if (map.containsKey(string)) {MutableInteger count = map.get(string);count.set(count.get() + 1);
} else {map.put(string, new MutableInteger(1));
}

要么

MutableInteger count = map.get(string);
if (count != null) {count.set(count.get() + 1);
} else {map.put(string, new MutableInteger(1));
}

在最坏的情况下,如果以前没有看到过密钥,则代码将搜索密钥两次:一次用于检索,一次用于设置。 它比上一个要好得多。 但是我们不应该立即满足并停止。 如果您在Java文档中选中了[Map.put()](http://docs.oracle.com/javase/7/docs/api/java/util/Map.html#put(K,V))方法,您会发现此方法将返回the previous value associated with key 。 这意味着我们可以将检索和设置合并为一个。 但是,您可能想知道:如果不首先检索计数器,如何设置新计数器? 现在,我们终于可以触摸本文中最棘手的部分:我们可以简化放置零频率计数器的工作!

public int incrementCount(K key, int count) {MutableInteger tmpCount = new MutableInteger(0);MutableInteger oldCount = map.put(key, tmpCount);if (oldCount != null) {count += oldCount.get();}tmpCount.set(count);return count;}

另一个柜台

看起来将所有必要的操作放入一个类中将对将来的使用有所帮助。 因此,我创建了一个称为Counter的类并将其公开。 计数器定义一个集合,该集合对对象出现在集合中的次数进行计数。 假设您有一个包含{a, a, b, c}的Counter。 在“ a”上调用getCount()将返回2,而在keySet()上调用将返回{a, b, c} 。 此类的工作方式类似于Map ,但是具有不同的方法来轻松获取/设置/增加对象的计数以及使用该计数来计算各种函数。 Counter构造函数和addAll()方法可用于复制另一个Counter的内容。 根据IntCounterAbstractMapBag修改Counter类。

Counter上的一些突出操作包括

  • gainCount()decrementCount() :将给定键的给定计数加/减到当前计数中。 如果之前没有看到该键,则假定它的计数为0,因此增量方法会将其计数设置为给定的数量。 减量会将其计数设置为-1。
  • getCount() :返回给定键的当前计数,如果以前没有看到过,则返回0。
  • keysAt()keysAbove()keysBelow() :返回其计数在给定阈值之上,之下或之下的一组键。 该集合可能包含0个元素,但不会为null。
  • argmin ()argmax() :找到并返回此Counter中具有最小/最大计数的密钥。 如果有几个最小/最大计数,则返回随机值。 如果此Counter为空,则返回null。
参考: 在Java中增加Map值的最有效方法–只需从PGuru博客的JCG合作伙伴 Peng Yifan那里 搜索一次密钥 。

翻译自: https://www.javacodegeeks.com/2013/10/most-efficient-way-to-increment-a-map-value-in-java-only-search-the-key-once.html

用Java递增Map值的最有效方法–仅搜索一次键相关推荐

  1. 结构为键值的map_在Java中增加Map值的最有效方法-只需搜索键一次

    结构为键值的map 这个问题可能被认为太基础了,但是在论坛中经常被问到. 在本文中,我将讨论一种仅在Map ONCE中搜索键的方法. 让我们首先来看一个例子. 假设我正在使用Map创建一个字符串频率列 ...

  2. java把map值放入vector_java把map值放入vector

    java把map值放入vector [2021-02-01 17:17:12]  简介: php去除nbsp的方法:首先创建一个PHP代码示例文件:然后通过"preg_replace(&qu ...

  3. Java 遍历Map常见的五种方法

    Java 遍历Map常见的四种方法 以下这种遍历是最常见的,也是我们经常使用的,在循环中需要使用健和值时,推荐使用这种方式 Map<Integer,Integer> map=new Has ...

  4. 已解决java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.util.Map异常的正确解决方法,亲测有效!!

    已解决java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.util.Map异常的正确解决方法,亲测有效!! ...

  5. Java遍历Map对象的四种方法

    在java中遍历Map有不少的方法.我们看一下最常用的方法及其优缺点. 既然java中的所有map都实现了Map接口,以下方法适用于任何map实现(HashMap, TreeMap, LinkedHa ...

  6. Java遍历Map集合的第二种方法Entry对象遍历Map集合内元素

    键值对方式:即通过集合中每个键值对(Entry)对象,获取键值对(Entry)对象中的键与值. 操作步骤: 获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回.方法提示:entry ...

  7. java把map值放入vector_Thinking in java基础之集合框架

    Thinking in java基础之集合框架 大家都知道我的习惯,先上图说话. 集合简介(容器) 把具有相同性质的一类东西,汇聚成一个整体,就可以称为集合,例如这里有20个苹果,我们把每一个苹果当成 ...

  8. java中Map遍历的四种方法

    在java中所有的map都实现了Map接口,因此所有的Map(如HashMap, TreeMap, LinkedHashMap, Hashtable等)都可以用以下的方式去遍历. 方法一:在for循环 ...

  9. java compareto 返回值_Java File compareTo()方法

    Java File compareTo()方法 java.io.File.compareTo(File pathname) 方法比较两个抽象路径名的字典顺序.用这种方法定义的排序是依赖于操作系统. 1 ...

最新文章

  1. 谈谈服务雪崩、降级与熔断
  2. 独家 | 基于知识蒸馏的BERT模型压缩
  3. 谁来谈谈Google Earth的核心技术和架构?(转)
  4. 判断一个变量类型是数组还是对象
  5. C语言面向对象编程(六):配置文件解析
  6. log4j.properties文件中的log4j.rootLogger重要性
  7. JavaScript日期格式化
  8. BZOJ_1096_[ZJOI2007]_仓库建设_(斜率优化动态规划+单调队列+特殊的前缀和技巧)
  9. SoapUI调试soap协议接口
  10. 基于永洪BI部署的自助分析平台(一)
  11. 【解决方案 二十五】如何对Excel表数据进行彻底转置
  12. 微信公众号网页开发和小程序开发之路
  13. 以首尾交换的方法交换字符串中以'A'开头和以'N'结尾的单词
  14. matlab imshow加画网格,matlab能生成随机行走网格吗? - 仿真模拟 - 小木虫 - 学术 科研 互动社区...
  15. 【Unity3D】基于AssetBundle实现资源热更新
  16. ThreadLocal学习笔记
  17. 蓝鲸智云-腾讯给广大运维工作者的福利
  18. js数组中添加新元素,如果没有则添加
  19. 如何使用MD5加密解密工具?
  20. 软件测试的底层逻辑思维是什么?

热门文章

  1. 作为 IT 行业的过来人,你有什么话想对后辈说的?2
  2. mysql fpmmm_zabbix配fpmmm(mpm)数据传送不了问题解决
  3. ToolProvider.getSystemJavaCompiler() return null 的解决方法
  4. streaming api_通过Spring Integration消费Twitter Streaming API
  5. 抽象工厂模式设计模式_21世纪的设计模式:抽象工厂模式
  6. java8 策略模式_Java 8中的策略模式
  7. r 数据框选子集_在带有组合框的值列表的下拉列表中显示显示属性的子集
  8. java se/ee_嗨,您好 。 。 ! 您如何评价Java / Java EE技能?
  9. NoSQL数据库程序员应该在2019年学习的5大知识
  10. java jvm调优_(第2部分,共3部分):有关性能调优,Java中的JVM,GC,Mechanical Sympathy等的文章和视频的摘要...