背景 大家好,我是棧長。 前些天,棧長給大家分享了兩篇有意思的文章: 帶了一個 3 年的開發,不會迴圈刪除 List 中的元素,我簡直崩潰!! 面試官:怎麼去除 List 中的重覆元素?我一行代碼搞定,趕緊拿去用! 這兩篇文章確實能幫助一大部分人,其中分享的一些實現技巧,編程很多年的高手也不一定用過 ...
背景
大家好,我是棧長。
前些天,棧長給大家分享了兩篇有意思的文章:
這兩篇文章確實能幫助一大部分人,其中分享的一些實現技巧,編程很多年的高手也不一定用過,不管自己水平多牛,還是多謙虛好學一些,掌握多一點總不是什麼壞事。
有粉絲建議棧長出一篇刪除 HashMap 裡面的數據,也有粉絲建議出一個系列的文章:
那這篇就分享下如何刪除 HashMap 中的元素吧!
PS: 這僅是我個人掌握的實現方案,不一定全,也不一定是最優的,歡迎大家分享,杠精勿擾。
HashMap 刪除元素方案
假設有以下數據:
public Map<String, String> initMap = new HashMap<>() {{
put("user1", "張三");
put("user2", "李四");
put("user3", "張三");
put("user4", "李四");
put("user5", "王五");
put("user6", "趙六");
put("user7", "李四");
put("user8", "王五");
}};
本文所有完整示例源代碼已經上傳:
歡迎 Star 學習,後面 Java 示例都會在這上面提供!
一般刪除 HashMap 集合中的元素,如果知道具體的 Key,並且需要根據 Key 刪除元素,使用 remove 方法就可以了。但是如何根據 Value 刪除 HashMap 集合中的元素呢?這才是你必須掌握的技巧!
1、使用 for 迴圈刪除
/**
* 使用 for 迴圈刪除
* @author: 棧長
* @from: 公眾號Java技術棧
*/
@Test
public void remove1() {
Set<Map.Entry<String, String>> entries = new CopyOnWriteArraySet<>(initMap.entrySet());
for (Map.Entry<String, String> entry : entries) {
if ("張三".equals(entry.getValue())) {
initMap.remove(entry.getKey());
}
}
System.out.println(initMap);
}
輸出結果:
使用 HashMap 中實現的 entrySet 方法獲取元素的集合,然後再進行迴圈遍歷,先根據 Value 值判斷要刪除的元素,然後再根據 Key 刪除元素。
在之前的文章中知道,增強的 for 迴圈底層使用的迭代器 Iterator,而 HashMap 是 fail-fast 類型的錯誤機制,所以遍歷時刪除元素會出現 java.util.ConcurrentModificationException
併發修改異常。
所以,這裡使用了線程安全的 CopyOnWriteArraySet 封裝了一層,避免出現併發修改異常,java.util.concurrent 包中的併發集合類都被設計為 fail-safe(安全失敗)類型的,比如 CopyOnWrite* 、ConcerrentHashMap 集合,遍歷過程中結構發生變更是安全的,不會拋出以上異常。
需要註意的是:
雖然 CopyOnWriteArraySet 併發性能很好,但每次刪除時都會複製一份同等集合,所以要考慮數據過多可能導致的記憶體消耗問題。具體使用和實現原理可以點擊該 CopyOnWriteArraySet 關鍵字鏈接看之前的文章,這裡不再撰述。
2、使用 forEach 迴圈刪除
/**
* 使用 forEach 迴圈刪除
* @author: 棧長
* @from: 公眾號Java技術棧
*/
@Test
public void remove2() {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>(initMap);
map.forEach((k, v) -> {
if ("張三".equals(v)) {
map.remove(k);
}
});
System.out.println(map);
}
輸出結果:
使用 HashMap 自帶的 forEach 迴圈刪除指定值的元素,這裡為什麼使用線程安全的 ConcurrentHashMap 集合包裝了一層,同樣是為了避免併發修改異常。ConcurrentHashMap 在各版本中都使用了最優的鎖設計方案,它的併發性能也是非常優異的。
另外,HashMap 和 ConcurrentHashMap 也是面試必問的,如果你近期準備面試跳槽,建議在Java面試庫小程式線上刷題,涵蓋 2000+ 道 Java 面試題,幾乎覆蓋了所有主流技術面試題。
3、使用 Iterator 迭代器刪除
/**
* 使用 Iterator 迭代器刪除
* @author: 棧長
* @from: 公眾號Java技術棧
*/
@Test
public void remove3() {
Iterator<Map.Entry<String, String>> iterator = initMap.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, String> entry = iterator.next();
if ("張三".equals(entry.getValue())) {
iterator.remove();
}
}
System.out.println(initMap);
}
輸出結果:
這種方式即正常使用迭代器遍歷刪除,它不會發生併發修改異常。
需要註意的是:
這種方法雖然不會發生併發修改異常,但 HashMap 並不是線程安全的,在迭代刪除元素時,另一個線程可能會刪除 HashMap 中的數據, 這時使用迭代器刪除同樣會導致併發修改異常。
所以,要保證線程安全的刪除,在創建迭代器之前,可以先用線程安全的 ConcurrentHashMap 集合包裝一層。或者使用 synchronized 關鍵字鎖住整個 Map。
如果沒有多線程修改環境,可以不用考慮。
4、使用 removeIf 刪除
/**
* 使用 removeIf 刪除
* @author: 棧長
* @from: 公眾號Java技術棧
*/
@Test
public void remove4() {
initMap.entrySet().removeIf(entry -> "張三".equals(entry.getValue()));
System.out.println(initMap);
}
輸出結果:
使用 entrySet 的 removeIf 刪除,它底層使用的是迭代器:
default boolean removeIf(Predicate<? super E> filter) {
Objects.requireNonNull(filter);
boolean removed = false;
final Iterator<E> each = iterator();
while (each.hasNext()) {
if (filter.test(each.next())) {
each.remove();
removed = true;
}
}
return removed;
}
所以,它和方法 3 是一樣的,只不過把條件寫成了 Predicate 函數式介面而已。
需要註意的是:
removeIf 雖然更方便了,但它仍然不是線程安全的,多線程場景參考方案同方法 3。
5、使用 Stream 刪除
/**
* 使用 Stream 刪除
* @author: 棧長
* @from: 公眾號Java技術棧
*/
@Test
public void remove5() {
Map<String, String> map = initMap.entrySet().stream()
.filter(entry -> !"張三".equals(entry.getValue()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
System.out.println(map);
}
輸出結果:
利用 Stream 的 filter 方法進行過濾,這個方法也十分簡單,一行代碼搞定。Stream 基礎就不介紹了,Stream 系列我之前寫過一個專題了,不懂的關註公眾號Java技術棧,然後在公眾號 Java 教程菜單中閱讀。
本文所有完整示例源代碼已經上傳:
歡迎 Star 學習,後面 Java 示例都會在這上面提供!
總結
本文總結了 5 種刪除 HashMap 元素的方法:
- 使用 for 迴圈刪除
- 使用 forEach 迴圈刪除
- 使用 Iterator 迭代器刪除
- 使用 removeIf 刪除
- 使用 Stream 刪除
實際開發過程中,可能會使用不同的遍歷方式,所以重點要考慮多線程場景,如果只是簡單的刪除元素,使用 removeIf 和 Stream 過濾是最省事的。
所以說,你身邊還有誰不會刪除 HashMap 中的元素?把這篇文章發給他吧,讓大家少走彎路,少寫垃圾代碼,共同進步。
你還知道哪些刪除技巧?歡迎留言分享~
好了,今天的分享就到這裡了,後面棧長會分享更多好玩的 Java 技術和最新的技術資訊,關註公眾號Java技術棧第一時間推送,我也將主流 Java 面試題和參考答案都整理好了,大家可以在Java面試庫小程式進行刷題。
最後,留個話題:
上面的種種方法雖然能刪除 HashMap 中指定值的元素,但是不能刪除所有的重覆元素,你覺得怎麼刪除重覆數據比較好?有哪些方案?
大家可以先討論下方案,下期分享,等棧長寫完,公眾號Java技術棧第一時間推送,不要走開~
版權聲明: 本文系公眾號 "Java技術棧" 原創,轉載、引用本文內容請註明出處,抄襲、洗稿一律投訴侵權,後果自負,並保留追究其法律責任的權利。
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2022最新版)
4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優雅的方式!!
覺得不錯,別忘了隨手點贊+轉發哦!