分享

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

 捡田螺的小男孩 2020-06-02

前言

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

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

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

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

  • 把map的键key转化为list

  • 把map的值value转化为list

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

伪代码如下:

  1. // key list

  2. List keyList = new ArrayList(map.keySet());

  3. // value list

  4. List valueList = new ArrayList(map.values());

  5. // key-value list

  6. List entryList = new ArrayList(map.entrySet());

示例代码:

  1. public class Test {

  2. public static void main(String[] args) {

  3. Map<Integer, String> map = new HashMap<>();

  4. map.put(2, "jay");

  5. map.put(1, "whx");

  6. map.put(3, "huaxiao");

  7. //把一个map的键转化为list

  8. List<Integer> keyList = new ArrayList<>(map.keySet());

  9. System.out.println(keyList);

  10. //把map的值转化为list

  11. List<String> valueList = new ArrayList<>(map.values());

  12. System.out.println(valueList);

  13. map的键值转化为list

  14. List entryList = new ArrayList(map.entrySet());

  15. System.out.println(entryList);


  16. }

  17. }

运行结果:

  1. [1, 2, 3]

  2. [whx, jay, huaxiao]

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

2、如何遍历一个Map

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

通过entrySet+for实现遍历

  1. for(Entry entry: map.entrySet()) {

  2. // get key

  3. K key = entry.getKey();

  4. // get value

  5. V value = entry.getValue();

  6. }

实例代码:

  1. public class EntryMapTest {

  2. public static void main(String[] args) {

  3. Map<Integer, String> map = new HashMap<>();

  4. map.put(2, "jay");

  5. map.put(1, "whx");

  6. map.put(3, "huaxiao");


  7. for(Map.Entry entry: map.entrySet()) {

  8. // get key

  9. Integer key = (Integer) entry.getKey();

  10. // get value

  11. String value = (String) entry.getValue();


  12. System.out.println("key:"+key+",value:"+value);

  13. }

  14. }

  15. }

通过Iterator+while实现遍历

  1. Iterator itr = map.entrySet().iterator();

  2. while(itr.hasNext()) {

  3. Entry entry = itr.next();

  4. // get key

  5. K key = entry.getKey();

  6. // get value

  7. V value = entry.getValue();

  8. }

实例代码:

  1. public class IteratorMapTest {

  2. public static void main(String[] args) {

  3. Map<Integer, String> map = new HashMap<>();

  4. map.put(2, "jay");

  5. map.put(1, "whx");

  6. map.put(3, "huaxiao");


  7. Iterator itr = map.entrySet().iterator();

  8. while(itr.hasNext()) {

  9. Map.Entry entry = (Map.Entry) itr.next();

  10. // get key

  11. Integer key = (Integer) entry.getKey();

  12. // get value

  13. String value = (String) entry.getValue();


  14. System.out.println("key:"+key+",value:"+value);

  15. }

  16. }

  17. }

运行结果:

  1. key:1,value:whx

  2. key:2,value:jay

  3. key:3,value:huaxiao

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

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

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

  1. List list = new ArrayList(map.entrySet());

  2. Collections.sort(list, (Entry e1, Entry e2)-> {

  3. return e1.getKey().compareTo(e2.getKey());

  4. });

实例代码:

  1. public class SortKeysMapTest {

  2. public static void main(String[] args) {

  3. Map<String, String> map = new HashMap<>();

  4. map.put("2010", "jay");

  5. map.put("1999", "whx");

  6. map.put("3010", "huaxiao");


  7. List<Map.Entry<String,String>> list = new ArrayList<>(map.entrySet());

  8. Collections.sort(list, (Map.Entry e1, Map.Entry e2)-> {

  9. return e1.getKey().toString().compareTo(e2.getKey().toString());

  10. });


  11. for (Map.Entry entry : list) {

  12. System.out.println("key:" + entry.getKey() + ",value:" + entry.getValue());

  13. }


  14. }

  15. }

使用SortedMap+TreeMap+Comparator实现

  1. SortedMap sortedMap = new TreeMap(new Comparator() {

  2. @Override

  3. public int compare(K k1, K k2) {

  4. return k1.compareTo(k2);

  5. }

  6. });

  7. sortedMap.putAll(map);

实例代码:

  1. public class SortKeys2MapTest {

  2. public static void main(String[] args) {

  3. Map<String, String> map = new HashMap<>();

  4. map.put("2010", "jay");

  5. map.put("1999", "whx");

  6. map.put("3010", "huaxiao");


  7. SortedMap sortedMap = new TreeMap(new Comparator<String>() {

  8. @Override

  9. public int compare(String k1, String k2) {

  10. return k1.compareTo(k2);

  11. }

  12. });

  13. sortedMap.putAll(map);


  14. Iterator itr = sortedMap.entrySet().iterator();

  15. while(itr.hasNext()) {

  16. Map.Entry entry = (Map.Entry) itr.next();

  17. // get key

  18. String key = (String) entry.getKey();

  19. // get value

  20. String value = (String) entry.getValue();


  21. System.out.println("key:"+key+",value:"+value);

  22. }

  23. }

  24. }

运行结果:

  1. key:1999,value:whx

  2. key:2010,value:jay

  3. key:3010,value:huaxiao

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

  1. List list = new ArrayList(map.entrySet());

  2. Collections.sort(list, (Entry e1, Entry e2) ->{

  3. return e1.getValue().compareTo(e2.getValue());

  4. });

实例代码:

  1. public class SortValuesMapTest {

  2. public static void main(String[] args) {

  3. Map<String, String> map = new HashMap<>();

  4. map.put("2010", "jay");

  5. map.put("1999", "whx");

  6. map.put("3010", "huaxiao");


  7. List <Map.Entry<String,String>>list = new ArrayList<>(map.entrySet());

  8. Collections.sort(list, (Map.Entry e1, Map.Entry e2)-> {

  9. return e1.getValue().toString().compareTo(e2.getValue().toString());

  10. }

  11. );


  12. for (Map.Entry entry : list) {

  13. System.out.println("key:" + entry.getKey() + ",value:" + entry.getValue());

  14. }

  15. }

  16. }

运行结果:

  1. key:3010,value:huaxiao

  2. key:2010,value:jay

  3. key:1999,value:whx

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

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

  1. public class Test1 {

  2. private static final Map <Integer,String>map;

  3. static {

  4. map = new HashMap<Integer, String>();

  5. map.put(1, "one");

  6. map.put(2, "two");

  7. }

  8. public static void main(String[] args) {

  9. map.put(3, "three");

  10. Iterator itr = map.entrySet().iterator();

  11. while(itr.hasNext()) {

  12. Map.Entry entry = (Map.Entry) itr.next();

  13. // get key

  14. Integer key = (Integer) entry.getKey();

  15. // get value

  16. String value = (String) entry.getValue();


  17. System.out.println("key:"+key+",value:"+value);

  18. }

  19. }

  20. }

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

  1. key:1,value:one

  2. key:2,value:two

  3. key:3,value:three

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

  1. public class Test2 {

  2. private static final Map<Integer, String> map;

  3. static {

  4. Map<Integer,String> aMap = new HashMap<>();

  5. aMap.put(1, "one");

  6. aMap.put(2, "two");

  7. map = Collections.unmodifiableMap(aMap);

  8. }


  9. public static void main(String[] args) {

  10. map.put(3, "3");

  11. Iterator itr = map.entrySet().iterator();

  12. while(itr.hasNext()) {

  13. Map.Entry entry = (Map.Entry) itr.next();

  14. // get key

  15. Integer key = (Integer) entry.getKey();

  16. // get value

  17. String value = (String) entry.getValue();


  18. System.out.println("key:"+key+",value:"+value);

  19. }

  20. }


  21. }

运行结果如下:

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

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


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

7、如何创建一个空map

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

  1. Map map=Collections.emptyMap();

  2. or

  3. Map<String,String> map=Collections.<String, String>emptyMap();

  4. //map1.put("1", "1"); 运行出错

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

  1. Map map = new HashMap();

8、有关于map的复制

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

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

  1. public class CopyMapAssignTest {

  2. public static void main(String[] args) {


  3. Map<Integer, User> userMap = new HashMap<>();


  4. userMap.put(1, new User("jay", 26));

  5. userMap.put(2, new User("fany", 25));


  6. //Shallow clone

  7. Map<Integer, User> clonedMap = userMap;


  8. //Same as userMap

  9. System.out.println(clonedMap);


  10. System.out.println("\nChanges reflect in both maps \n");


  11. //Change a value is clonedMap

  12. clonedMap.get(1).setName("test");


  13. //Verify content of both maps

  14. System.out.println(userMap);

  15. System.out.println(clonedMap);

  16. }

  17. }

运行结果:

  1. {1=User{name='jay', age=26}, 2=User{name='fany', age=25}}


  2. Changes reflect in both maps


  3. {1=User{name='test', age=26}, 2=User{name='fany', age=25}}

  4. {1=User{name='test', age=26}, 2=User{name='fany', age=25}}

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

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

  1. public class CopyCloneMapTest {

  2. public static void main(String[] args) {

  3. HashMap<Integer, User> userMap = new HashMap<>();


  4. userMap.put(1, new User("jay", 26));

  5. userMap.put(2, new User("fany", 25));


  6. //Shallow clone

  7. HashMap<Integer, User> clonedMap = (HashMap<Integer, User>) userMap.clone();


  8. //Same as userMap

  9. System.out.println(clonedMap);


  10. System.out.println("\nChanges reflect in both maps \n");


  11. //Change a value is clonedMap

  12. clonedMap.get(1).setName("test");


  13. //Verify content of both maps

  14. System.out.println(userMap);

  15. System.out.println(clonedMap);

  16. }

  17. }

运行结果:

  1. {1=User{name='jay', age=26}, 2=User{name='fany', age=25}}


  2. Changes reflect in both maps


  3. {1=User{name='test', age=26}, 2=User{name='fany', age=25}}

  4. {1=User{name='test', age=26}, 2=User{name='fany', age=25}}

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

例子三,通过putAll操作

  1. public class CopyPutAllMapTest {

  2. public static void main(String[] args) {

  3. HashMap<Integer, User> userMap = new HashMap<>();


  4. userMap.put(1, new User("jay", 26));

  5. userMap.put(2, new User("fany", 25));


  6. //Shallow clone

  7. HashMap<Integer, User> clonedMap = new HashMap<>();

  8. clonedMap.putAll(userMap);


  9. //Same as userMap

  10. System.out.println(clonedMap);


  11. System.out.println("\nChanges reflect in both maps \n");


  12. //Change a value is clonedMap

  13. clonedMap.get(1).setName("test");


  14. //Verify content of both maps

  15. System.out.println(userMap);

  16. System.out.println(clonedMap);

  17. }

  18. }

运行结果:

  1. {1=User{name='jay', age=26}, 2=User{name='fany', age=25}}


  2. Changes reflect in both maps


  3. {1=User{name='test', age=26}, 2=User{name='fany', age=25}}

  4. {1=User{name='test', age=26}, 2=User{name='fany', age=25}}

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

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

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

  1. public class CopyDeepMapTest {


  2. public static void main(String[] args) {

  3. HashMap<Integer, User> userMap = new HashMap<>();


  4. userMap.put(1, new User("jay", 26));

  5. userMap.put(2, new User("fany", 25));


  6. //Shallow clone

  7. Gson gson = new Gson();

  8. String jsonString = gson.toJson(userMap);


  9. Type type = new TypeToken<HashMap<Integer, User>>(){}.getType();

  10. HashMap<Integer, User> clonedMap = gson.fromJson(jsonString, type);


  11. //Same as userMap

  12. System.out.println(clonedMap);


  13. System.out.println("\nChanges reflect in only one map \n");


  14. //Change a value is clonedMap

  15. clonedMap.get(1).setName("test");


  16. //Verify content of both maps

  17. System.out.println(userMap);

  18. System.out.println(clonedMap);

  19. }

  20. }

运行结果:

  1. {1=User{name='jay', age=26}, 2=User{name='fany', age=25}}


  2. Changes reflect in only one map


  3. {1=User{name='jay', age=26}, 2=User{name='fany', age=25}}

  4. {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

个人公众号

  • 如果你是个爱学习的好孩子,可以关注我公众号,一起学习讨论。

  • 如果你觉得本文有哪些不正确的地方,可以评论,也可以关注我公众号,私聊我,大家一起学习进步哈。

    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约