一、簡(jiǎn)述
Java 的 map 遍歷有多種方法共耍,如最早的 Iterator,Java5 支持的 foreach,Java8 的 Lambda夷野。HashMap 遍歷從大的方向可分為以下 4 類(lèi):
- 迭代器(Iterator)方式遍歷;
- for each 方式遍歷荣倾;
- Lambda 表達(dá)式遍歷(JDK8+)悯搔;
- Streams API 遍歷(JDK8+)。
但每種類(lèi)型下又有不同的實(shí)現(xiàn)方式,因此具體的遍歷方式又可分為:
- 使用迭代器(Iterator)EntrySet 的方式進(jìn)行遍歷妒貌。
- 使用迭代器(Iterator)KeySet 的方式進(jìn)行遍歷通危。
- 使用 for each EntrySet 的方式進(jìn)行遍歷。
- 使用 for each KeySet 的方式進(jìn)行遍歷灌曙。
- 使用 Lambda 表達(dá)式的方式進(jìn)行遍歷菊碟。
public class TestMap {
public static Map<String, String> map = new HashMap<String, String>();
map.put("1", "大象");
map.put("2", "猴子");
map.put("3", "老虎");
}
二、entrySet
通過(guò)對(duì) map entrySet 的遍歷在刺,可以同時(shí)拿到 key 和 value逆害。這一般是最常見(jiàn)也是最可取的遍歷方式,在鍵值都需要時(shí)使用蚣驼。一般情況下魄幕,性能上要優(yōu)于方法二。
// entrySet 獲取key and value
public void testEntry() {
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
三颖杏、keySet values
如果只需要 map 的 key 或者 value纯陨,用 map 的 keySet 或 values 方法無(wú)疑是最方便的,而不是用 entrySet留储。
Map<String, String> map = new HashMap<String, String>();
//遍歷map中的鍵
for (String key : map.keySet()) {
System.out.println("Key = " + key);
}
//遍歷map中的值
for (String value : map.values()) {
System.out.println("Value = " + value);
}
如果需要同時(shí)獲取 key 和 value翼抠,也可以先獲取 key,然后再通過(guò) map 的 get(key) 獲取 value获讳。作為方法一的替代阴颖,此代碼更簡(jiǎn)潔,但實(shí)際上它相當(dāng)慢且無(wú)效率丐膝。因?yàn)橛面I取值是耗時(shí)的操作(與方法一相比膘盖,在不同的 Map 實(shí)現(xiàn)中該方法慢了20%~200%)。該方法不是最優(yōu)選擇尤误,一般不推薦使用侠畔。
// keySet get(key) 獲取key and value
public void testKeySetAndGetKey() {
for (String key : map.keySet()) {
System.out.println(key + ":" + map.get(key));
}
}
四、Iterator
對(duì)于上面的幾種 foreach 都可以用 Iterator 代替损晤,其實(shí) foreach 在 Java5 中才被支持软棺,foreach 的寫(xiě)法看起來(lái)更簡(jiǎn)潔。
但 Iterator 也有其優(yōu)勢(shì):在用 foreach 遍歷 map 時(shí)尤勋,如果改變其大小喘落,會(huì)報(bào)錯(cuò)。但如果只是刪除元素最冰,可以使用 Iterator 的 remove 方法刪除元素瘦棋,根據(jù) javadoc 的說(shuō)明,如果在 foreach 遍歷中嘗試使用此方法暖哨,結(jié)果是不可預(yù)測(cè)的赌朋。
// Iterator entrySet 獲取key and value
//Iterator:業(yè)務(wù)復(fù)雜的可以用while
public void testIterator() {
Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, String> entry = it.next();
System.out.println(entry.getKey() + ":" + entry.getValue());
// it.remove(); 刪除元素
}
}
//Iterator:普通的可以用foreach遍歷
for(Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();it.hasNext();){
Map.Entry<String,String> entry = it.next();
System.out.println(entry.getKey() + ":" + entry.getValue());
//it.remove(); 會(huì)拋java.util.ConcurrentModificationException
}
五、Lambda~流式 map 遍歷(Java8)
Java8 提供了 Lambda 表達(dá)式支持,語(yǔ)法更簡(jiǎn)潔沛慢,可以同時(shí)拿到 key 和 value赡若。不過(guò),經(jīng)測(cè)試性能低于 entrySet团甲,所以更推薦用 entrySet 的方式逾冬。
// Lambda 獲取key and value
//流式一:
public void testLambda() {
map.forEach((key, value) -> {
System.out.println(key + ":" + value);
});
}
//流式二:Streams API 單線程
map.entrySet().stream().forEach(entry->{
System.out.println("code:"+entry.getKey()+" desc:"+entry.getValue());
});
//流式三:Streams API 多線程
map.entrySet().parallelStream().forEach((entry) -> {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
});
六、小結(jié)
- 如果只是獲取 key 或 value躺苦,推薦使用 keySet 或 values 方式身腻。
- 如果同時(shí)需要 key 和 value 推薦使用 entrySet。
- 如果需要在遍歷過(guò)程中刪除元素推薦使用 Iterator匹厘。
- 如果需要在遍歷過(guò)程中增加元素霸株,可以新建一個(gè)臨時(shí) map 存放新增的元素,等遍歷完畢集乔,再把臨時(shí) map 放到原來(lái)的 map 中。
七坡椒、Java 中兩個(gè) map 比較
1??用 map 的 keySet() 的迭代器(性能效率較低)
public void compareMap1() {
Map<String, String> m1 = new HashMap<String, String>();//小
Map<String, String> m2 = new HashMap<String, String>();//大
Iterator<String> iter1 = m1.keySet().iterator();
while (iter1.hasNext()) {
String m1Key = iter1.next();
//若兩個(gè)map中相同key對(duì)應(yīng)的value不相等
if (!m1.get(m1Key).equals(m2.get(m1Key))) {
//......
}
}
}
2??用 map 的 entrySet() 的迭代器(性能效率較高)
public void compareMap2() {
Map<String, String> m1 = new HashMap<String, String>();
Map<String, String> m2 = new HashMap<String, String>();
Iterator<Map.Entry<String, String>> iter1 = m1.entrySet().iterator();
while (iter1.hasNext()) {
Map.Entry<String, String> entry1 = iter1.next();
String m1value = entry1.getValue() == null ? "" : entry1.getValue();
String m2value = m2.get(entry1.getKey()) == null ? "" : m2.get(entry1.getKey());
//若兩個(gè)map中相同key對(duì)應(yīng)的value不相等
if (!m1value.equals(m2value)) {
//其他操作...
}
}
}
3??用 map 的 entrySet() 的增強(qiáng)型 for 循環(huán)(性能效率較高)
public void compareMap3() {
Map<String, String> m1 = new HashMap<String, String>();
Map<String, String> m2 = new HashMap<String, String>();
for (Map.Entry<String, String> entry1 : m1.entrySet()) {
String m1value = entry1.getValue() == null ? "" : entry1.getValue();
String m2value = m2.get(entry1.getKey()) == null ? "" : m2.get(entry1.getKey());
//若兩個(gè)map中相同key對(duì)應(yīng)的value不相等
if (!m1value.equals(m2value)) {
//其他操作...
}
}
}