Map类简介:
可以实现key-value的结构;
HashMap 根据key的hash分配地址,所以key不可重复 & 存储是无序的;
IdentityHashMap key可以重复
TreeMap 按照key升序分布,key不可重复
Map使用实例
遍历时更新Map , 抛出异常ConcurrentModificationException
Map<String, String> myMap = new IdentityHashMap<String, String>();/*初始化*/
myMap.put("a","aa");
myMap.put("b","bb");
myMap.put("c","cc");
myMap.put("d","dd");
for(Map.Entry<String, String> entry: myMap.entrySet()){
String k = entry.getKey().toString();
String v = entry.getValue().toString();
if(k == "b"){
myMap.remove(k); /*失败,抛出异常ConcurrentModificationException*/
}
}
道听途说,修改代码,用迭代器遍历:
Iterator<Entry<String, String>> it = myMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
String k = entry.getKey().toString();
if(k.indexOf("b")!=-1) {
it.remove(); /*成功*/
//myMap.remove(k); /*失败,抛出异常ConcurrentModificationException*/
}
}
原因分析:
为了防止在遍历Map的时候对象被其它线程改动,Map类引入参数
modCount(记录Map结构变化的次数)。
IdentityHashMap.put(K key, V value)与IdentityHashMap.remove(Object key)等都会导致modCount++。
当遍历时发现modCount变化了(
modCount != expectedModCount),就会抛出异常ConcurrentModificationException。
而it.remove();成功,是因为Iterator.remove()方法会在删除当前迭代对象的同时维护索引的一致性 并且 重新同步modCount值;
解决方案:
/**
* 解决方案:
* 深度clone出来tmpMap,遍历tmpMap同时修改myMap
* (浅度克隆:只是复制对象的引用,指向同一内存(如))
* */
Map<String,String> tmpMap = new IdentityHashMap<String, String>();
tmpMap.putAll(myMap);
for(Map.Entry<String, String> entry: myMap.entrySet()){
if(entry.getKey().toString() == "c")
myMap.put("cc", "ccc");/*遍历tmpMap,修改myMap*/
}
那么for-each与Iterator有什么区别?
没区别,java的for-each其实也是利用Iterator迭代。
如:此处执行流程一模一样(entrySet().iterator().nextIndex()),两者等同,只是更加简洁而已。
Map排序
若Map的key是不重复的,直接赋值给TreeMap
若Map的key是重复的
未完待续...