前言

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

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, "java");map.put(1, "HTML");map.put(3, "CSS");//把一个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]
[java, HTML, CSS]
[1=java, 2=HTML, 3=CSS]

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, "java");map.put(1, "HTML");map.put(3, "CSS");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, "java");map.put(1, "HTML");map.put(3, "CSS");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:HTML
key:2,value:java
key:3,value:CSS

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", "java");map.put("1999", "HTML");map.put("3010", "CSS");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", "java");map.put("1999", "HTML");map.put("3010", "CSS");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:HTML
key:2010,value:java
key:3010,value:CSS

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", "java");map.put("1999", "HTMl");map.put("3010", "CSS");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:CSS
key:2010,value:java
key:1999,value:HTML

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 DO NOT reflect in other 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 DO NOT reflect in other 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

被面试官问到 Map 相关问题,Map 应该掌握的8个问题相关推荐

  1. 后处理程序文件大小的变量_【每日一题】(17题)面试官问:JS中事件流,事件处理程序,事件对象的理解?...

    关注「松宝写代码」,精选好文,每日一题 作者:saucxs | songEagle 2020,实「鼠」不易 2021,「牛」转乾坤 风劲潮涌当扬帆,任重道远须奋蹄! 一.前言 2020.12.23 立 ...

  2. 【020期】面试官问:Java 遍历 Map 集合有几种方式?效率如何?

    >>号外:关注"Java精选"公众号,回复"2021面试题",领取免费资料!"Java精选面试题"小程序,3000+ 道面试题在 ...

  3. hashmap扩容_面试官问:HashMap在并发情况下为什么造成死循环?一脸懵

    这个问题是在面试时常问的几个问题,一般在问这个问题之前会问Hashmap和HashTable的区别?面试者一般会回答:hashtable是线程安全的,hashmap是线程不安全的. 那么面试官就会紧接 ...

  4. 当面试官问Webpack的时候他想知道什么

    希沃ENOW大前端 公司官网:CVTE(广州视源股份) 前言 在前端工程化日趋复杂的今天,模块打包工具在我们的开发中起到了越来越重要的作用,其中webpack就是最热门的打包工具之一. 说到webpa ...

  5. 【255期】面试官问:MyBatis 二级缓存,如何实现关联刷新功能?

    点击上方"Java精选",选择"设为星标" 别问别人为什么,多问自己凭什么! 下方有惊喜,留言必回,有问必答! 每一天进步一点点,是成功的开始... 1.MyB ...

  6. 【192期】面试官问:说说 Tomcat 组成与工作原理?

    点击上方"Java精选",选择"设为星标" 别问别人为什么,多问自己凭什么! 下方有惊喜,留言必回,有问必答! 每天 08:15 更新文章,每天进步一点点... ...

  7. 面试官问你想找什么工作_找工作时如何面试面试官

    面试官问你想找什么工作 在技​​术面试中要问的十二个问题 (Twelve questions to ask at tech interviews) I've just come off six wee ...

  8. 面试官问我,Redis分布式锁如何续期?懵了。

    作者:肥朝,来自:肥朝(ID:feichao_java) 前言 上一篇[面试官问我,使用Dubbo有没有遇到一些坑?我笑了.]之后,又有一位粉丝和我说在面试过程中被虐了.鉴于这位粉丝是之前肥朝的老粉丝 ...

  9. java执行sql文件_面试官问你MyBatis SQL是如何执行的?把这篇文章甩给他

    初识 MyBatis MyBatis 是第一个支持自定义 SQL.存储过程和高级映射的类持久框架.MyBatis 消除了大部分 JDBC 的样板代码.手动设置参数以及检索结果.MyBatis 能够支持 ...

  10. 大叔手记(10):别再让面试官问你单例

    大叔手记(10):别再让面试官问你单例(暨6种实现方式让你堵住面试官的嘴) ... 2012-2-19 09:03| 发布者: benben| 查看: 283| 评论: 0 摘要: 引子经常从Recr ...

最新文章

  1. PUTTY工具的使用
  2. spring源码深度解析—Spring的整体架构和环境搭建
  3. Linux下常用的压缩与解压命令
  4. C++11 并发指南一(C++11 多线程初探)
  5. 开源跳板机(堡垒机)Jumpserver v0.3.0 发布
  6. 状态机设计的一般步骤_浅谈状态机
  7. visual c++ 技术资料(网络收集)
  8. 字体方向 道路标注_自动驾驶环境感知的“见闻色”——3D点云标注
  9. columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by 版本mysql8.0
  10. 关于Angular样式封装
  11. android之sqlite操作
  12. 一个操作共享内存的类!可以方面的添加,删除数据,包括各种结构体!
  13. java获取文本文件的编码格式
  14. su必备插件_会了这10个插件,Sketchup也能玩飞起来!
  15. 金葵花股票资金操盘大赛3号选手张朝阳关于疫情对A股市场影响的观点
  16. UI设计--蓝湖切图
  17. 学习springboot第一天
  18. 头歌HTML实训笔录
  19. 如何用Eclipse创建一个JavaSwing的项目
  20. 2023考研数学真题及答案解析!

热门文章

  1. LeetCode_1046_最后一块石头的重量
  2. c语言如何删除链表中内容,C语言删除双向链表中数据项程序
  3. 小贴士丨夏季空调使用小窍门,省电又舒适
  4. MATLAB中griddata和griddatan插值函数简单说明
  5. Linux 内存映射mmap,内存映射mmap
  6. 冷笑话之--漂流瓶与恶魔
  7. matlab读取.dat数据
  8. 病例讨论-----鼻窦炎一例(联想的风)
  9. C++getline用法
  10. Tensorflow图像识别 Tensorflow手写体识别(二)