点击上方 好好学java ,选择 星标 公众号

重磅资讯、干货,第一时间送达
今日推荐:一个线程池 bug 引发的 GC 思考!个人原创+1博客:点击前往,查看更多

前言

最近几天看了几篇有关于Java Map的外国博文,写得非常不错,所以整理了Java map 应该掌握的8个问题,都是日常开发司空见惯的问题,希望对大家有帮助;如果有不正确的地方,欢迎提出,万分感谢哈~

本章节所有代码demo已上传github

1、如何把一个Map转化为List

日常开发中,我们经常遇到这种场景,把一个Map转化为List。map转List有以下三种转化方式:

  • 把map的键key转化为list

  • 把map的值value转化为list

  • 把map的键值key-value转化为list

伪代码如下:

// key list
List keyList = new ArrayList(map.keySet());
// value list
List valueList = new ArrayList(map.values());
// key-value list
List entryList = new ArrayList(map.entrySet());

示例代码:

public class Test {public static void main(String[] args) {Map<Integer, String> map = new HashMap<>();map.put(2, "jay");map.put(1, "whx");map.put(3, "huaxiao");//把一个map的键转化为listList<Integer> keyList = new ArrayList<>(map.keySet());System.out.println(keyList);//把map的值转化为listList<String> valueList = new ArrayList<>(map.values());System.out.println(valueList);把map的键值转化为listList entryList = new ArrayList(map.entrySet());System.out.println(entryList);}
}

运行结果:

[1, 2, 3]
[whx, jay, huaxiao]
[1=whx, 2=jay, 3=huaxiao]

2、如何遍历一个Map

我们经常需要遍历一个map,可以有以下两种方式实现:

通过entrySet+for实现遍历

for(Entry entry: map.entrySet()) {// get keyK key = entry.getKey();// get valueV value = entry.getValue();
}

实例代码:

public class EntryMapTest {public static void main(String[] args) {Map<Integer, String> map = new HashMap<>();map.put(2, "jay");map.put(1, "whx");map.put(3, "huaxiao");for(Map.Entry entry: map.entrySet()) {// get keyInteger key = (Integer) entry.getKey();// get valueString value = (String) entry.getValue();System.out.println("key:"+key+",value:"+value);}}
}

通过Iterator+while实现遍历

Iterator itr = map.entrySet().iterator();
while(itr.hasNext()) {Entry entry = itr.next();// get keyK key = entry.getKey();// get valueV value = entry.getValue();
}

实例代码:

public class IteratorMapTest {public static void main(String[] args) {Map<Integer, String> map = new HashMap<>();map.put(2, "jay");map.put(1, "whx");map.put(3, "huaxiao");Iterator itr = map.entrySet().iterator();while(itr.hasNext()) {Map.Entry entry = (Map.Entry) itr.next();// get keyInteger key = (Integer) entry.getKey();// get valueString value = (String) entry.getValue();System.out.println("key:"+key+",value:"+value);}}
}

运行结果:

key:1,value:whx
key:2,value:jay
key:3,value:huaxiao

3、如何根据Map的keys进行排序

对Map的keys进行排序,在日常开发很常见,主要有以下两种方式实现。

把Map.Entry放进list,再用Comparator对list进行排序

List list = new ArrayList(map.entrySet());
Collections.sort(list, (Entry e1, Entry e2)-> {return e1.getKey().compareTo(e2.getKey());
});

实例代码:

public class SortKeysMapTest {public static void main(String[] args) {Map<String, String> map = new HashMap<>();map.put("2010", "jay");map.put("1999", "whx");map.put("3010", "huaxiao");List<Map.Entry<String,String>> list = new ArrayList<>(map.entrySet());Collections.sort(list, (Map.Entry e1, Map.Entry e2)-> {return e1.getKey().toString().compareTo(e2.getKey().toString());});for (Map.Entry entry : list) {System.out.println("key:" + entry.getKey() + ",value:" + entry.getValue());}}
}

使用SortedMap+TreeMap+Comparator实现

SortedMap sortedMap = new TreeMap(new Comparator() {@Overridepublic int compare(K k1, K k2) {return k1.compareTo(k2);}
});
sortedMap.putAll(map);

实例代码:

public class SortKeys2MapTest {public static void main(String[] args) {Map<String, String> map = new HashMap<>();map.put("2010", "jay");map.put("1999", "whx");map.put("3010", "huaxiao");SortedMap sortedMap = new TreeMap(new Comparator<String>() {@Overridepublic int compare(String k1, String k2) {return k1.compareTo(k2);}});sortedMap.putAll(map);Iterator itr = sortedMap.entrySet().iterator();while(itr.hasNext()) {Map.Entry entry = (Map.Entry) itr.next();// get keyString key = (String) entry.getKey();// get valueString value = (String) entry.getValue();System.out.println("key:"+key+",value:"+value);}}
}

运行结果:

key:1999,value:whx
key:2010,value:jay
key:3010,value:huaxiao

4、如何对Map的values进行排序

List list = new ArrayList(map.entrySet());
Collections.sort(list, (Entry e1, Entry e2) ->{return e1.getValue().compareTo(e2.getValue());});

实例代码:

public class SortValuesMapTest {public static void main(String[] args) {Map<String, String> map = new HashMap<>();map.put("2010", "jay");map.put("1999", "whx");map.put("3010", "huaxiao");List <Map.Entry<String,String>>list = new ArrayList<>(map.entrySet());Collections.sort(list, (Map.Entry e1, Map.Entry e2)-> {return e1.getValue().toString().compareTo(e2.getValue().toString());});for (Map.Entry entry : list) {System.out.println("key:" + entry.getKey() + ",value:" + entry.getValue());}}
}

运行结果:

key:3010,value:huaxiao
key:2010,value:jay
key:1999,value:whx

5、如何初始化一个静态/不可变的Map

初始化一个静态不可变的map,单单static final+static代码块还是不行的,如下:

public class Test1 {private static final Map <Integer,String>map;static {map = new HashMap<Integer, String>();map.put(1, "one");map.put(2, "two");}public static void main(String[] args) {map.put(3, "three");Iterator itr = map.entrySet().iterator();while(itr.hasNext()) {Map.Entry entry = (Map.Entry) itr.next();// get keyInteger key = (Integer) entry.getKey();// get valueString value = (String) entry.getValue();System.out.println("key:"+key+",value:"+value);}}
}

这里面,map继续添加元素(3,"three"),发现是OK的,运行结果如下:

key:1,value:one
key:2,value:two
key:3,value:three

真正实现一个静态不可变的map,需要Collections.unmodifiableMap,代码如下:

public class Test2 {private static final Map<Integer, String> map;static {Map<Integer,String> aMap = new HashMap<>();aMap.put(1, "one");aMap.put(2, "two");map = Collections.unmodifiableMap(aMap);}public static void main(String[] args) {map.put(3, "3");Iterator itr = map.entrySet().iterator();while(itr.hasNext()) {Map.Entry entry = (Map.Entry) itr.next();// get keyInteger key = (Integer) entry.getKey();// get valueString value = (String) entry.getValue();System.out.println("key:"+key+",value:"+value);}}
}

运行结果如下:

可以发现,继续往map添加元素是会报错的,实现真正不可变的map。

6、HashMap, TreeMap, and Hashtable,ConcurrentHashMap的区别

HashMap TreeMap Hashtable ConcurrentHashMap
有序性
null k-v 是-是 否-是 否-否 否-否
线性安全
时间复杂度 O(1) O(log n) O(1) O(log n)
底层结构 数组+链表 红黑树 数组+链表 红黑树

7、如何创建一个空map

如果map是不可变的,可以这样创建:

Map map=Collections.emptyMap();
or
Map<String,String> map=Collections.<String, String>emptyMap();
//map1.put("1", "1"); 运行出错

如果你希望你的空map可以添加元素的,可以这样创建

Map map = new HashMap();

8、有关于map的复制

有关于hashmap的复制,在日常开发中,使用也比较多。主要有 =,clone,putAll,但是他们都是浅复制,使用的时候注意啦,可以看一下以下例子:

例子一,使用=复制一个map:

public class CopyMapAssignTest {public static void main(String[] args) {Map<Integer, User> userMap = new HashMap<>();userMap.put(1, new User("jay", 26));userMap.put(2, new User("fany", 25));//Shallow cloneMap<Integer, User> clonedMap = userMap;//Same as userMapSystem.out.println(clonedMap);System.out.println("\nChanges reflect in both maps \n");//Change a value is clonedMapclonedMap.get(1).setName("test");//Verify content of both mapsSystem.out.println(userMap);System.out.println(clonedMap);}
}

运行结果:

{1=User{name='jay', age=26}, 2=User{name='fany', age=25}}
Changes reflect in both maps
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}

从运行结果看出,对cloneMap修改,两个map都改变了,所以=是浅复制。

例子二,使用hashmap的clone复制:

public class CopyCloneMapTest {public static void main(String[] args) {HashMap<Integer, User> userMap = new HashMap<>();userMap.put(1, new User("jay", 26));userMap.put(2, new User("fany", 25));//Shallow cloneHashMap<Integer, User> clonedMap = (HashMap<Integer, User>) userMap.clone();//Same as userMapSystem.out.println(clonedMap);System.out.println("\nChanges reflect in both maps \n");//Change a value is clonedMapclonedMap.get(1).setName("test");//Verify content of both mapsSystem.out.println(userMap);System.out.println(clonedMap);}
}

运行结果:

{1=User{name='jay', age=26}, 2=User{name='fany', age=25}}
Changes reflect in both maps
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}

从运行结果看出,对cloneMap修改,两个map都改变了,所以hashmap的clone也是浅复制。

例子三,通过putAll操作

public class CopyPutAllMapTest {public static void main(String[] args) {HashMap<Integer, User> userMap = new HashMap<>();userMap.put(1, new User("jay", 26));userMap.put(2, new User("fany", 25));//Shallow cloneHashMap<Integer, User> clonedMap = new HashMap<>();clonedMap.putAll(userMap);//Same as userMapSystem.out.println(clonedMap);System.out.println("\nChanges reflect in both maps \n");//Change a value is clonedMapclonedMap.get(1).setName("test");//Verify content of both mapsSystem.out.println(userMap);System.out.println(clonedMap);}
}

运行结果:

{1=User{name='jay', age=26}, 2=User{name='fany', age=25}}
Changes reflect in both maps
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}

从运行结果看出,对cloneMap修改,两个map都改变了,所以putAll还是浅复制。

那么,如何实现深度复制呢?

可以使用序列化实现,如下为谷歌Gson序列化HashMap,实现深度复制的例子:

public class CopyDeepMapTest {public static void main(String[] args) {HashMap<Integer, User> userMap = new HashMap<>();userMap.put(1, new User("jay", 26));userMap.put(2, new User("fany", 25));//Shallow cloneGson gson = new Gson();String jsonString = gson.toJson(userMap);Type type = new TypeToken<HashMap<Integer, User>>(){}.getType();HashMap<Integer, User> clonedMap = gson.fromJson(jsonString, type);//Same as userMapSystem.out.println(clonedMap);System.out.println("\nChanges reflect in only one map \n");//Change a value is clonedMapclonedMap.get(1).setName("test");//Verify content of both mapsSystem.out.println(userMap);System.out.println(clonedMap);}
}

运行结果:

{1=User{name='jay', age=26}, 2=User{name='fany', age=25}}
Changes reflect in only one map
{1=User{name='jay', age=26}, 2=User{name='fany', age=25}}
{1=User{name='test', age=26}, 2=User{name='fany', age=25}}

从运行结果看出,对cloneMap修改,userMap没有被改变,所以是深度复制。

参考与感谢

  • Top 9 questions about Java Maps

  • Best way to create an empty map in Java

  • How to clone HashMap – Shallow and Deep Copy

有关于Java Map,应该掌握的8个问题相关推荐

  1. Java map 知识

    Java map: Map 接口中键和值一一映射. 可以通过键来获取值 map 的方法如下: 序号 方法描述 1 void clear( )  从此映射中移除所有映射关系(可选操作). 2 boole ...

  2. java map 教程_Java Map接口

    Java Map接口 在本教程中,我们将学习Java Map接口及其方法. Java collections框架的Map接口提供了Map数据结构的功能. 它实现了Collection接口. map的工 ...

  3. java 轻量级map,java Map 遍历速度最优解

    java Map 遍历速度最优解 第一种: Map map = new HashMap(); Iterator iter = map.entrySet().iterator(); while (ite ...

  4. Java Map集合面试题汇总

    转载自 Java Map集合面试题汇总 1. 你都知道哪些常用的Map集合? 2.Collection集合接口和Map接口有什么关系? 3.HashMap是线程安全的吗?线程安全的Map都有哪些?性能 ...

  5. BAT Java面试笔试33题:JavaList、Java Map等经典面试题!答案汇总!

    JavaList面试题汇总 1.List集合:ArrayList.LinkedList.Vector等. 2.Vector是List接口下线程安全的集合. 3.List是有序的. 4.ArrayLis ...

  6. Java Map中那些巧妙的设计

    简介: 他山之石可以攻玉,这些巧妙的设计思想非常有借鉴价值,可谓是最佳实践.然而,大多数有关Java Map原理的科普类文章都是专注于"点",并没有连成"线", ...

  7. ​Java Map中那些巧妙的设计

    最近拜读了一些Java Map的相关源码,不得不惊叹于JDK开发者们的鬼斧神工.他山之石可以攻玉,这些巧妙的设计思想非常有借鉴价值,可谓是最佳实践.然而,大多数有关Java Map原理的科普类文章都是 ...

  8. Java Map 自定义排序

    HashMap是不保证顺序的,要有顺序,要用LinkedHashMap,这是按照插入顺序排列的. Map接口的哈希表和链接列表实现,具有可预知的迭代顺序.此实现与HashMap的不同之处在于,后者维护 ...

  9. java:Map借口及其子类HashMap五,identityHashMap子类

    java:Map借口及其子类HashMap五,identityHashMap子类 了解:identityHashMap子类 一般情况下,标准的Map,是不会有重复的key值得value的,相同的key ...

最新文章

  1. Asp.net中具体的日期格式化用法
  2. ISME:中科院微生物所揭示细菌利用光能新机制!
  3. 安装Win8后必做的优化
  4. linux下的各种shell介绍(bash和dash转换)
  5. 理解有参构造器和无参构造器的作用
  6. 学习React基本渲染数据操作(-)
  7. LightOJ 1071 Baker Vai(记忆化搜索)
  8. 网易微专业python数据分析_网易微专业_Python数据分析师 01 数据思维导论:如何从数据中挖掘价值?...
  9. 【案例】这些日赚上万美金Youtube油管从业者 技术人的福音
  10. codeforces 1139c Edgy Trees 【并查集 】
  11. 11 wifi6速率_实测:华硕、华为、小米、水星,千元以内的wifi6路由器哪家强?...
  12. 深度学习AI美颜系列---人脸数据增强
  13. 51单片机定时时间的计算
  14. 用骈文写一段自我检讨
  15. 谷歌提供的地理位置信息和反地理位置信息
  16. 单片机tcp ip协议c语言,单片机上简单TCPIP协议的实现.PDF
  17. 【游戏体验】Infiltraing the Airship(火柴人潜入飞船)
  18. 30个新职业薪酬出炉,程序员霸屏
  19. 基于蚁群算法的六轴机械臂路径规划(运动学模型建立)
  20. 华中师范大学计算机考研874攻略

热门文章

  1. SUMO输出车辆相关参数
  2. CAN总线基础(二)——CAN总线物理层介绍(总线电压详解)
  3. 蓝牙mesh — 解密蓝牙mesh系列文章汇总
  4. vmalloc 实现
  5. c语言编程基本概念,读朱兆祺攻破C语言之一----编程基本概念
  6. 卡尔曼滤波器算法(Kalman Filter)—— 数学推导,图文并茂
  7. [力扣leetcode319]灯泡问题
  8. [Java基础]Map集合的遍历
  9. python报错:UnicodeDecodeError: ‘ascii‘ codec can‘t decode byte 0xe0 in position 0: ordinal not in rang
  10. linux kernel变长数组使用示例