2019独角兽企业重金招聘Python工程师标准>>>

Java中的Map和Set有不少相似之处。本文将分享一个把Map类转化成Set类的小技巧。

或许你已经知道,HashSet其实是一个披着Set方法外衣的HashMap;同样,TreeSet其实也是一个披着Set方法外衣的TreeMap。Map并不支持直接用迭代器进行遍历,因此下面的这段代码编译无法通过:

1

2

3

Map<String, Double> salaries = new HashMap<>();

for(double salary : salaries) { // does not compile

}

我们可以通过遍历Map中的key集合、value集合和entry集合来实现Map的遍历。由于Map中的value是可以重复出现的,因此values()方法返回的是一个Collection类型的集合。而Map中的key是不允许重复的,因此keySet()方法和entrySet()返回的都是Set类型的集合。

因此,我们可以采用下面的方法来遍历Map:

1

2

3

Map<String, Double> salaries = new HashMap<>();

for (double salary : salaries.values()) {

}

或者可以通过遍历key来遍历Map:

1

2

3

Map<String, Double> salaries = new HashMap<>();

for (String name : salaries.keySet()) {

}

当然,还可以通过遍历entry来遍历Map:

1

2

3

4

5

Map<String, Double> salaries = new HashMap<>();

for (Map.Entry<String, Double> entry : salaries.entrySet()) {

  String name = entry.getKey();

  double salary = entry.getValue();

}

我经常看到程序员这样遍历Map:先获取keySet,然后对keys进行遍历,并通过get()方法找到对应的value。

1

2

3

4

Map<String, Double> salaries = new HashMap<>();

for (String name : salaries.keySet()) { // less efficient way to

    double salary = salaries.get(name);   // iterate over entries

}

从直观上看,采用遍历entry的方式遍历Map会更加高效一些,这种遍历方式的时间复杂度是O(n)。然而,如果HashMap中的元素分布均匀,调用get()方法查找元素的时间复杂度将是O(1),那么这两种方法遍历HashMap的时间复杂度是一样的,都是O(n)。这两种遍历方式虽然有所不同,但时间复杂度都是线性的。但这个结论并不适用于其它类型的Map,特别是TreeMap。TreeMap的平均查找效率是O(log n),因此通过keySet遍历TreeMap的时间复杂度是O(n x log n)。

java.util包中有很多Map类,其中一些Map类有着对应类型的Set类实现,例如TreeMap和HashMap。这些Set类都是基于对应的Map类实现的,因此它们和对应的Map类保持相同的算法复杂度以及并发特性。

本文的重点来了。我在完成并发专修课程中的某道练习题时,需要一个快速高效并且线程安全的HashSet。起初,我直接把ConcurrentHashMap当作Set用,把要插入Set的元素以Key的形式插入Map,Key所对应的Value则是一个无意义的默认值。后来我发现,Java 6中的java.util.Collections类提供了一个newSetFromMap()方法,该方法能够基于指定的Map对象创建一个新的Set对象。在创建这个Map<K, V>对象时,K的数据类型必须与你想要创建的Set中元素的数据类型一致;而V必须是Boolean类型的,这是因为value字段用于标记该元素是否存在。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

import java.util.*;

import java.util.concurrent.*;

public class ConcurrentSetTest {

    public static void main(String[] args) {

        Set<String> names = Collections.newSetFromMap(

            new ConcurrentHashMap<String, Boolean>()

        );

        names.add("Brian Goetz");

        names.add("Victor Grazi");

        names.add("Heinz Kabutz");

        names.add("Brian Goetz");

        System.out.println("names = " + names);

    }

}

当然,newSetFromMap()方法只能返回标准Set接口类型的对象。如果你的Map类有着更丰富的接口(与标准Map<K, V>接口相比),你还是需要自行封装实现对应的Set类。

希望读者能从本文中有所收获。如果你曾经为找不到ConcurrentHashSet而烦恼,现在你就可以自己创建一个了。

欢迎工作一到五年的Java工程师朋友们加入Java架构开发:855801563

群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代

转载于:https://my.oschina.net/u/3959491/blog/2252640

如何用Map对象创建Set对象相关推荐

  1. 实例:使用纹理对象创建Sprite对象

    精灵类是Sprite,它的类图如下图所示: Sprite类直接继承了Node类,具有Node基本特征.此外,我们还可以看到Sprite类的派生类有:PhysicsSprite和Skin.Physics ...

  2. java string对象创建_String对象创建个数

    s = new String("xyz");创建了几个String Object?两个对象,一个是"xyx",一个是指向"xyx"的引用对象 ...

  3. python创建对象教程_python源码学习 之 对象创建和对象的行为

    在将对象的创建和行为之前,我们先来看一下类型对象,python是弱类型语言,但并不代表python没有类型,python中处理对象的类型有一个专门的对象,我们称之为类型对象,如果不知道对象的类型就无法 ...

  4. JVM篇--详解对象创建过程-对象结构-对象访问方式

    hello,hello,刚学过的东西瞬间忘记,是我年龄大了还是年龄大了,可我明明才20出头啊(凑不要脸),其实25了,偏题了....今天整理一下关于JVM对象篇的结构,会记录对象创建过程,还有对象的内 ...

  5. java创建一个不可变对象_使用不可变对象创建值对象

    java创建一个不可变对象 在回答我最近的文章中AutoValue:生成的不可变的值类 , 布兰登认为,这可能是有趣的,看看如何AutoValue比较项目Lombok和Immutables和凯文借调这 ...

  6. 使用不可变对象创建值对象

    在回答我最近的文章中AutoValue:生成的不可变的值类 , 布兰登认为,这可能是有趣的,看看如何AutoValue比较项目Lombok和Immutables和凯文借调这一点. 我同意这是一个好主意 ...

  7. java-第十章-类和对象-创建管理员对象

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 package 上机练习; public c ...

  8. 【Android Protobuf 序列化】Protobuf 使用 ( Protobuf 源码分析 | 创建 Protobuf 对象 )

    文章目录 一.Protobuf 源码分析 二.创建 Protobuf 对象 三.完整代码示例 四.参考资料 一.Protobuf 源码分析 Protobuf 源文件如下 : addressbook.p ...

  9. 在 Java 中,为什么需要创建内部类对象之前需要先创建外部类对象

    在 Java 中,为什么需要创建内部类对象之前需要先创建外部类对象   我们知道,在 Java 中,创建一个内部类对象之前,需要它的一个外部类对象.这是因为内部类可能使用外部类的数据.   在内部类中 ...

最新文章

  1. NTU课程笔记 mas714复习:例题
  2. pandas 中的函数—— .reset_index()
  3. Flex与.NET互操作(九):FluorineFx.NET的认证(Authentication )与授权(Authorization)
  4. 设计模式- 策略模式
  5. YUV420数据格式
  6. 使用LinkedHashMap的Code4ReferenceList最近使用(LRU)实现
  7. linux单网卡多拨Adsl,ROS单线多拨pppoe
  8. 非使用FindControl方法找到深层嵌套的控件
  9. catch 语句的参数
  10. php伪静态规则生成,SEO工具箱:PHP自动生成PHPCMS伪静态规则.htaccess
  11. sql server2008数据库迁移的两种方案
  12. ORACLE 常用操作命令
  13. Jsonviewer2 for Notepad++ 64 bit/位
  14. 【dbv】使用dbv工具检验数据文件是否有坏块
  15. 苹果iOS越狱后没有声音的解决办法
  16. 微软高性能计算新贵WHS2008
  17. qq登录界面句柄_注册QQ飞车日服账号
  18. 武汉工程大计算机学校地址,武汉工程学院
  19. Sigmastar 方案的相机开发流程和注意点
  20. Christian band介绍

热门文章

  1. 20162303 实验二 树
  2. 【图论】求无向连通图的割点
  3. .NET Web实时消息后台服务器推送技术-GoEasy
  4. 20135302魏静静——linux课程第三周实验及总结
  5. leetcode Sudoku java
  6. WINDOWS2003自动开关机的实现
  7. http请求中get和post方法的区别
  8. keras指定gpu_keras不使用gpu,但tensorflow
  9. 一个咸鱼的python_一个咸鱼的Python爬虫之路(三):爬取网页图片
  10. 为何大佬都愿意为“996”站台?中国的程序员活该加班?