关于Java Map应该掌握的问题
Posted zifei399
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于Java Map应该掌握的问题相关的知识,希望对你有一定的参考价值。
-
如何把一个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
- (
- " Changes reflect in both maps "
- );
- //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
- (
- " Changes reflect in both maps "
- );
- //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
- (
- " Changes reflect in both maps "
- );
- //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
- (
- " Changes reflect in only one map "
- );
- //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没有被改变,所以是深度复制
-
以上是关于关于Java Map应该掌握的问题的主要内容,如果未能解决你的问题,请参考以下文章
Java 集合框架帮你搞通哈希表,掌握 Map 和 Set 的使用(内含哈希表源码解读及面试常考题)