今天花了一些时间写了Map遍历的几种方法,比较了各个方法的运行效率,本来想把各个遍历方法的运行效率(时间比较)贴出来的,但是运行的时候外部影响较多所以就没有贴出实际的测试运行数据。这些信息对我们还是有很大帮助的,因为当我们做大型软件开发的时候代码优化、SQL优化及其重要,这个时候就离不开从可以中选择最优的一种方法来实现需求;在写的时候我也有些不知道,不知道的我都是通过JavaAPI来查阅相关的资料,查阅过按理解写了代码之后就会啦!O(∩_∩)O哈哈~API是个好东西哦!大家好好利用。这些分享希望对大家有所帮助。
1、Iterator
public interface Iterator
对 collection 进行迭代的迭代器。迭代器取代了 Java Collections Framework 中的 Enumeration。迭代器与枚举有两点不同:
a:迭代器允许调用者利用定义良好的语义在迭代期间从迭代器所指向的 collection 移除元素。
b:方法名称得到了改进。
方法摘要:标红色的为常用
|
|
---|---|
|
boolean hasNext() 如果仍有元素可以迭代,则返回 true。 |
|
E next() 返回迭代的下一个元素。 |
|
void remove() 从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。 |
2、Map
Map接口中键和值一一映射. 可以通过键来获取值。
a:给定一个键和一个值,你可以将该值存储在一个Map对象. 之后,你可以通过键来访问对应的值。
c:当访问的值不存在的时候,方法就会抛出一个NoSuchElementException异常.
d:当对象的类型和Map里元素类型不兼容的时候,就会抛出一个 ClassCastException异常。
e:当在不允许使用Null对象的Map中使用Null对象,会抛出一个NullPointerException 异常。
f:当尝试修改一个只读的Map时,会抛出一个UnsupportedOperationException异常。
方法摘要:标红色的为常用
|
|
---|---|
|
void clear() 从此映射中移除所有映射关系(可选操作)。 |
|
boolean containsKey( Object key) 如果此映射包含指定键的映射关系,则返回 true。 |
|
boolean containsValue( Object value) 如果此映射将一个或多个键映射到指定值,则返回 true。 |
|
Set 返回此映射中包含的映射关系的 Set 视图。 |
|
boolean equals( Object o) 比较指定的对象与此映射是否相等。 |
|
V get(Object key)返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null 。 |
|
int hashCode() 返回此映射的哈希码值。 |
|
boolean isEmpty() 如果此映射未包含键-值映射关系,则返回 true。 |
|
Set 返回此映射中包含的键的 Set 视图。 |
|
V put(K key,V values) 将指定的值与此映射中的指定键关联(可选操作)。 |
|
void putAll( Map extends K,? extends V> m) 从指定映射中将所有映射关系复制到此映射中(可选操作)。 |
|
V remove( Object key) 如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。 |
|
int size() 返回此映射中的键-值映射关系数。 |
|
Collection 返回此映射中包含的值的 Collection 视图。 |
3、Map.Entry
public static interface Map.Entry
映射项(键-值对)。Map.entrySet 方法返回映射的 collection 视图,其中的元素属于此类。获得映射项引用的唯一 方法是通过此 collection 视图的迭代器来实现。这些 Map.Entry 对象仅 在迭代期间有效;更确切地讲,如果在迭代器返回项之后修改了底层映射,则某些映射项的行为是不确定的,除了通过setValue 在映射项上执行操作之外。
方法摘要:标红色的为常用
|
|
---|---|
|
boolean equals( Object o) 比较指定对象与此项的相等性。 |
|
K getKey() 返回与此项对应的键。 |
|
V getValues() 返回与此项对应的值。 |
|
int hashCode() 返回此映射项的哈希码值。 |
|
V setValue(V value) 用指定的值替换与此项对应的值(可选操作)。 |
4、Iterator、Map、Map.Entry的综合运用
以遍历Map的集合来分析:
方法一
在for-each循环中使用entries来遍历. 这是最常见的并且在大多数情况下也是最可取的遍历方式。在键值都需要时使用。
注意:for-each循环在java 5中被引入所以该方法只能应用于java 5或更高的版本中。如果你遍历的是一个空的map对象,for-each循环将抛出NullPointerException,因此在遍历前你总是应该检查空引用。
public static void testMap1(Map
System.out.println("第一种遍历:");
for (Map.Entry
{
System.out.println("key:" + entry.getKey() + "value:" + entry.getValue());
}
}
方法二
在for-each循环中遍历keys或values。如果只需要map中的键或者值,你可以通过keySet或values来实现遍历,而不是用entrySet。该方法比entrySet遍历在性能上稍好(快了10%),而且代码更加干净。
private static void testMap2(Map
System.out.println("第二种遍历:");
for (Object key : map.keySet())
{
System.out.println("key:" + key);
}
for (Object value : map.values())
{
System.out.println("value:" + value);
}
}
方法三
使用Iterator遍历,使用泛型遍历map。
public static void testMap3(Map
System.out.println("第三种遍历:");
Iterator
while (iterator.hasNext())
{
Map.Entry
System.out.println("key:" + entry.getKey() + "value:" + entry.getValue());
}
}
方法四
使用Iterator不使用泛型遍历,你也可以在keySet和values上应用同样的方法。
该种方式看起来冗余却有其优点所在。首先,在老版本java中这是惟一遍历map的方式。另一个好处是,你可以在遍历时调用iterator.remove()来删除entries,另两个方法则不能。根据javadoc的说明,如果在for-each遍历中尝试使用此方法,结果是不可预测的。从性能方面看,该方法类同于for-each遍历(即方法二)的性能。
@SuppressWarnings("rawtypes")
private static void testMap4(Map
System.out.println("第四种遍历:");
Iterator iterator=map.entrySet().iterator();
while(iterator.hasNext())
{
Map.Entry entry=(Entry) iterator.next();
System.out.println("key:" + entry.getKey() + "value:" + entry.getValue());
}
}
方法五
作为方法一的替代,这个代码看上去更加干净;但实际上它相当慢且无效率。因为从键取值是耗时的操作(与方法一相比,在不同的Map实现中该方法慢了20%~200%)。如果你安装了FindBugs,它会做出检查并警告你关于哪些是低效率的遍历。所以尽量避免使用。
private static void testMap5(Map
System.out.println("第五种遍历:");
for(Object key:map.keySet())
{
Object value=map.get(key);
System.out.println("key:" + key + "value:" + value);
}
}
5、总结
各个方法各有优点,按实际需要选择。