前言

最近几天看了几篇有关于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
);
        
}
    
}

}

运行结果如下:

可以发现,继续往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

个人公众号

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