Set和HashMap
发现 Set和HashMap之间还是有很多需要注意的地方:
HashMap<String,String> map = new HashMap<String,String>();
map.put("1", "11");
map.put("2", "22");
map.put("3", "33");
Set<String> set = map.keySet();
1. map的keySet()方法只返回一个set实例,所以当从key1中删除一个对象时候,其他也将会受到影响。map里面的元素收到影响;
2. 针对于 set不能进行 add操作 ,否则会报“java.lang.UnsupportedOperationException” 。原因 如下 :
public Set<K> keySet()返回此映射中所包含的键的 set 视图。该集合受映射的支持,所以映射的变化也反映在该集合中,反之亦然。该集合支持元素的移除,通过 Iterator.remove、Set.remove、removeAll、retainAll 和 clear 操作,从该映射中移除相应的映射关系。它不支持 add 或 addAll 操作。
3.
Set<String> set= map.keySet();
for (String key : set) {
map.remove(key);
}
此代码 报这个异常: Exception in thread "main" java.util.ConcurrentModificationException
at java.util.HashMap$HashIterator.nextEntry(Unknown Source)
at java.util.HashMap$KeyIterator.next(Unknown Source)
at com.nan.an.jing.TestSet.main(TestSet.java:23)
原因 为 : 因为删除了一个Entry之后,因为ketSet不正确,在for循环时出的问题。
改正的方法为:
String[] keySet = map.keySet().toArray(new String[0]);
for (String key : keySet) {
map.remove(key);
}
或者
Object[] keySet = map.keySet().toArray();
for (Object key : keySet) {
map.remove((String)key);
}
附注 : 代码实例
- package com.nan.an.jing;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.Map.Entry;
- import java.util.Set;
- public class TestSet {
- public static void main(String[] args) {
- HashMap<String,String> map = new HashMap<String,String>();
- map.put("1", "aa");
- map.put("2", "bb");
- map.put("3", "aa");
- map.remove("1");
- //必须转换为array,或者 String[] keySet = map.keySet().toArray(new String[0]);
- Object[] keySet = map.keySet().toArray();
- for (Object key : keySet) {
- map.remove((String)key);
- }
- System.out.println(map);
- // set仅仅一个实例,set删除,map也跟随删除
- Set<String> set = map.keySet();
- set.remove("1");
- System.out.println(set);
- System.out.println(map);
- // 采用 iterator方法删除 map
- for(Iterator<String> iterator = set.iterator();iterator.hasNext();)
- {
- iterator.next();
- iterator.remove();
- }
- System.out.println(map);
- // 采用iterator方法获取map信息
- Set<Entry<String, String$amp;>amp;$gt; set0 = map.entrySet();
- for(Iterator<Map.Entry<String, String$amp;>amp;$gt; iterator = set0.iterator();iterator.hasNext();){
- Map.Entry<String, String> mm = iterator.next();
- String key1 = mm.getKey();
- String value = mm.getValue();
- }
- System.out.println(set0);
- // 采用list增加元素
- HashMap<String,String> map1 = new HashMap<String,String>();
- map1.put("1", "aa");
- map1.put("2", "bb");
- Set<String> set1 = map1.keySet();
- List<String> ll = new ArrayList<String>();
- for(String ss : set1){
- ll.add(ss);
- }
- ll.add("cc");
- System.out.println(ll);
- System.out.println(map1);
- }
- }
如何遍历???
或许你已经知道,HashSet其实是一个披着Set方法外衣的HashMap;同样,TreeSet其实也是一个披着Set方法外衣的TreeMap。Map并不支持直接用迭代器进行遍历,因此下面的这段代码编译无法通过:
1 2 3 |
|
我们可以通过遍历Map中的key集合、value集合和entry集合来实现Map的遍历。由于Map中的value是可以重复出现的,因此values()方法返回的是一个Collection类型的集合。而Map中的key是不允许重复的,因此keySet()方法和entrySet()返回的都是Set类型的集合。
因此,我们可以采用下面的方法来遍历Map:
1 2 3 |
|
或者可以通过遍历key来遍历Map:
1 2 3 |
|
当然,还可以通过遍历entry来遍历Map:
1 2 3 4 5 |
|
我经常看到程序员这样遍历Map:先获取keySet,然后对keys进行遍历,并通过get()方法找到对应的value。
1 2 3 4 |
|
从直观上看,采用遍历entry的方式遍历Map会更加高效一些,这种遍历方式的时间复杂度是O(n)。然而,如果HashMap中的元素分布均匀,调用get()方法查找元素的时间复杂度将是O(1),那么这两种方法遍历HashMap的时间复杂度是一样的,都是O(n)。这两种遍历方式虽然有所不同,但时间复杂度都是线性的。但这个结论并不适用于其它类型的Map,特别是TreeMap。TreeMap的平均查找效率是O(log n),因此通过keySet遍历TreeMap的时间复杂度是O(n x log n)。