背景
大家好,我是堆疊長,
前些天,堆疊長給大家分享了兩篇有意思的文章:
- 帶了一個 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", "王五");
}};
本文所有完整示例源代碼已經上傳:
https://github.com/javastacks/javastack
歡迎 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 教程選單中閱讀,
本文所有完整示例源代碼已經上傳:
https://github.com/javastacks/javastack
歡迎 Star 學習,后面 Java 示例都會在這上面提供!
總結
本文總結了 5 種洗掉 HashMap 元素的方法:
- 使用 for 回圈洗掉
- 使用 forEach 回圈洗掉
- 使用 Iterator 迭代器洗掉
- 使用 removeIf 洗掉
- 使用 Stream 洗掉
實際開發程序中,可能會使用不同的遍歷方式,所以重點要考慮多執行緒場景,如果只是簡單的洗掉元素,使用 removeIf 和 Stream 過濾是最省事的,
所以說,你身邊還有誰不會洗掉 HashMap 中的元素?把這篇文章發給他吧,讓大家少走彎路,少寫垃圾代碼,共同進步,
你還知道哪些洗掉技巧?歡迎留言分享~
好了,今天的分享就到這里了,后面堆疊長會分享更多好玩的 Java 技術和最新的技術資訊,關注公眾號Java技術堆疊第一時間推送,我也將主流 Java 面試題和參考答案都整理好了,大家可以在Java面試庫小程式進行刷題,
最后,留個話題:
上面的種種方法雖然能洗掉 HashMap 中指定值的元素,但是不能洗掉所有的重復元素,你覺得怎么洗掉重復資料比較好?有哪些方案?
大家可以先討論下方案,下期分享,等堆疊長寫完,公眾號Java技術堆疊第一時間推送,不要走開~
著作權宣告: 本文系公眾號 "Java技術堆疊" 原創,轉載、參考本文內容請注明出處,抄襲、洗稿一律投訴侵權,后果自負,并保留追究其法律責任的權利,
近期熱文推薦:
1.1,000+ 道 Java面試題及答案整理(2022最新版)
2.勁爆!Java 協程要來了,,,
3.Spring Boot 2.x 教程,太全了!
4.別再寫滿屏的爆爆爆炸類了,試試裝飾器模式,這才是優雅的方式!!
5.《Java開發手冊(嵩山版)》最新發布,速速下載!
覺得不錯,別忘了隨手點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/545184.html
標籤:其他
