Map是一个包含key-value对集合的数据结构,并且key唯一。下面是map的常用方式:
一、Map转为List
Map接口提供了三个集合视图:key集合、value集合、key-value集合。它们都可以通过一个构造函数或者调用addAll()方法转换为List。
// ksy List List keyList = new ArrayList(map.keySet()); // value List List valueList = new ArrayList(map.valueSet()); // key-value List List entryList = new ArrayList(map.entrySet());
二、遍历Map中的Entry
遍历Map即遍历kye-value对,这些pairs存储在Map.Entry中,Map.entrySet()返回一个key-value集合,以下是最有效的遍历entry的方式
for(Entry entry : map.entrySet()){ // get key K key = entry.getKey(); // get value V value = entry.getValue(); }
也可以使用迭代器,尤其是在JDK1.5以前的版本
Iterator itr = map.entrySet().iterator(); while(itr.hasNext()){ Entry entry = itr.next(); // get key K key = entry.getKey(); // get value V value = netry.getValue(); }
三、按key值排序Map
常用方法是将Map.Entry放在一个List里,然后使用一个Comparator排序这些值
List list = new ArrayList(map.entrySet()); Collections.sort(list,new Comparator()) { @Override public int compare(Entry e1, Entry e2){ return e1.getKey().compareTo(e2.getKey()); } }
另一种方法是使用SortedMap,提供了keys上的全排序,因此所有的keys或者实现了Comparable或者可以作为被comparator接收。
TreeMap是SortedMap的一个实现类,他的构造函数可以接收comparator。
下面代码实现了普通Map到SortedMap的转换。
SortedMap sortedMap = new TreeMap(new Comparator()) { // @Override public int compare(K k1, K k2) { return k1.compareTo(k2); } }
四、按values排序Map
将Map放入List然后排序它,不过这次我们比较的是Entry.getValue()。
List list = new ArrayList(map.entrySet()); Collections.sort(list,new Comparator()) { @Override public int compare(Entry e1, Entry e2){ return e1.getValue().compareTo(e2.getValue()); } }
我们也可以使用sorted map解决这个问题,前提是values也是唯一的。满足了这个条件,就可以将key=value转换为value=key,这中方法有很大局限性,因此不建议使用。
五、static/immutable Map的初始化
如果希望一个Map是constant的,最好的方法是将它copy给一个immutable map
初始化一个static/immutable map,可以使用一个static的initializer(如下代码)。但是这段代码是有问题的,尽管map被声明为static final,但是仍然可以对它进行操作,因此不没有真正实现immutable。使用一个static的initializer创建immutable map,我们还需要一个额外的anonymous class,并在初始化的最后一步将它copy到一个unmodifiable map里。这样如果在对m该ap进行操作就会抛出UnsupportedOperationException错误。
// wrong code public class Test { private static final Map map; static { map = new HashMap(); map.put(1, "one"); map.put(2, "two"); } } // right code public class Test { private static final Map map; static { Map aMap = new HashMap(); aMap.put(1, "one"); aMap.put(2, "two"); map = collections.unmodifiableMap(aMap); } }
六、HashMap、TreeMap、HashTable的比较
1. 迭代顺序:HashMap和HashTable不能保证原来map的顺序,TreeMap根据key的自然序或者comparator遍历整个entry;
2. key-value权限:HashMap允许可以key和value都为null(只有key为null也可以)。HashTable不允许key或value为null;如果HashTable使用自然徐序或它的comparator时不允许key为null,会抛出异常;
3.同步:只用HashTable是同步的,其它都不同步。所以如果不需要考虑线程安全的话,推荐使用HashMap,代替HashTable。
HashMap | HashTable | TreeMap | |
Iterator order | no | no | yes |
null key-value | yes-yes | no-no | no-yes |
synchronized | no | yes | no |
time performance | o(1) | o(1) | o(log n) |
implementation | buckets | buckets | red-black tree |
七、反向Map
有时候我们需要map的value是唯一的,也就是说one-to-one Map,可以通过value找到key,这种数据结构叫做bidirectional map,不过JDK现在还不支持这种数据结构。
Apache Common Collection和Guava 提供了这种数据结构,分别叫BidiMap和BiMap。
八、Map的浅拷贝
java中大部分Map的实现都提供了一个拷贝构造函数,但是这个拷贝过程不是同步的,为了避免这种不同步拷贝,可以使用Collections.synchronizedMap()。
Map copiedMap = Collections.synchronizedMap(map);
另一个有趣的方法是使用clone()方法,但是不推荐使用,引用Josh Bloch(Java Collection框架的设计者)在“Copy construct versus cloning”中的以一句话:
I often provide a public clone method on concrete classes because people expect it....It's a shame that Cloneable is broken,but it happens....Cloneable is a weak spot, and I think people should be aware of its limitations.
既然大牛不建议了,这里也就不讲了。呵呵。。。
九、创建一个空Map
如果map是静态的,使用:
map = Collections.emptyMap();
否则,使用任何一个实现均可,如:
map = new HashMap();