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

osc_a7a1prn6 2020-11-08 12:06:40
java github entry treemap gson


前言

最近几天看了几篇有关于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的键转化为list
List
<
Integer
>
keyList
=
new
ArrayList
<>(
map
.
keySet
());
System
.
out
.
println
(
keyList
);
//把map的值转化为list
List
<
String
>
valueList
=
new
ArrayList
<>(
map
.
values
());
System
.
out
.
println
(
valueList
);
把
map
的键值转化为
list
List
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 key
K key
=
entry
.
getKey
();
// get value
V 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 key
Integer
key
=
(
Integer
)
entry
.
getKey
();
// get value
String
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 key
K key
=
entry
.
getKey
();
// get value
V 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 key
Integer
key
=
(
Integer
)
entry
.
getKey
();
// get value
String
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
()
{
@Override
public
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
>()
{
@Override
public
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 key
String
key
=
(
String
)
entry
.
getKey
();
// get value
String
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 key
Integer
key
=
(
Integer
)
entry
.
getKey
();
// get value
String
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 key
Integer
key
=
(
Integer
)
entry
.
getKey
();
// get value
String
value
=
(
String
)
entry
.
getValue
();
System
.
out
.
println
(
"key:"
+
key
+
",value:"
+
value
);
}
}
}

运行结果如下:
有关于Java Map,应该掌握的8个问题

可以发现,继续往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 clone
Map
<
Integer
,
User
>
clonedMap
=
userMap
;
//Same as userMap
System
.
out
.
println
(
clonedMap
);
System
.
out
.
println
(
"\nChanges reflect in both maps \n"
);
//Change a value is clonedMap
clonedMap
.
get
(
1
).
setName
(
"test"
);
//Verify content of both maps
System
.
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 clone
HashMap
<
Integer
,
User
>
clonedMap
=
(
HashMap
<
Integer
,
User
>)
userMap
.
clone
();
//Same as userMap
System
.
out
.
println
(
clonedMap
);
System
.
out
.
println
(
"\nChanges reflect in both maps \n"
);
//Change a value is clonedMap
clonedMap
.
get
(
1
).
setName
(
"test"
);
//Verify content of both maps
System
.
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 clone
HashMap
<
Integer
,
User
>
clonedMap
=
new
HashMap
<>();
clonedMap
.
putAll
(
userMap
);
//Same as userMap
System
.
out
.
println
(
clonedMap
);
System
.
out
.
println
(
"\nChanges reflect in both maps \n"
);
//Change a value is clonedMap
clonedMap
.
get
(
1
).
setName
(
"test"
);
//Verify content of both maps
System
.
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 clone
Gson
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 userMap
System
.
out
.
println
(
clonedMap
);
System
.
out
.
println
(
"\nChanges reflect in only one map \n"
);
//Change a value is clonedMap
clonedMap
.
get
(
1
).
setName
(
"test"
);
//Verify content of both maps
System
.
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个问题

  • 如果你是个爱学习的好孩子,可以关注我公众号,一起学习讨论。
  • 如果你觉得本文有哪些不正确的地方,可以评论,也可以关注我公众号,私聊我,大家一起学习进步哈。
版权声明
本文为[osc_a7a1prn6]所创,转载请带上原文链接,感谢
https://my.oschina.net/u/4402060/blog/4708089

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云