一口氣帶你踩完五個 List 的大坑,真的是處處坑啊!|原創

2020-08-28 樓下小黑哥

List 可謂是我們經常使用的集合類之一,幾乎所有業務代碼都離不開 List。既然天天在用,那就沒準就會踩中這幾個 List 常見坑。

今天我們就來總結這些常見的坑在哪裡,撈自己一手,防止後續同學再繼續踩坑。

本文設計知識點如下:

List 踩坑大全

ArrayList 這是李逵,還是李鬼?

以前實習的時候,寫過這樣一段簡單代碼,通過 ArraysasList 返回明明也是一個 ArrayList,為什麼添加一個元素就會報錯?這以後還能好好新增元素嗎?

最後通過 Debug 才發現這個ArraysasList產生新集合與原始數組互相影響之外,JDK 另一個方法 ListsubList 實現方式,可以發現這個 SubList 內部有一個 parent 欄位保存保存最原始 List 。

image-20200419163334939

所有外部讀寫動作看起來是在操作 SubList ,實際上底層動作卻都發生在原始 List 中,比如 add 方法:

另外由於 SubList 實際上還在引用原始 List,業務開發中,如果不注意,很可能產生 OOM 問題。

以下例子來自於極客時間:Java業務開發常見錯誤100例

private static List<List<Integer>> data = new ArrayList<>();private static void oom() {    for (int i = 0; i < 1000; i++) {        List<Integer> rawList = IntStream.rangeClosed(1, 100000).boxed().collect(Collectors.toList());        data.add(rawList.subList(0, 1));    }}

data 看起來最終保存的只是 1000 個具有 1 個元素的 List,不會佔用很大空間。但是程序很快就會 OOM

OOM 的原因正是因為每個 SubList 都強引用個一個 10 萬個元素的原始 List,導致 GC 無法回收。

這裡修復的辦法也很簡單,跟上面一樣,也來個套娃唄,加一層 ArrayList 。

不可變集合,說好不變,你怎麼就變了

為了防止 List 集合被誤操作,我們可以使用 CollectionsunmodifiableList 產生不可變集合將會被原始 List 所影響。

查看 Collectionsof 方法。

List<String> list = new ArrayList<>(Arrays.asList(&34;, &34;, &34;));List<String> unmodifiableList = List.of(list.toArray(new String[]{}));

使用 Guava immutable list

List<String> list = new ArrayList<>(Arrays.asList(&34;, &34;, &34;));List<String> unmodifiableList = ImmutableList.copyOf(list);

相比而言 Guava 方式比較清爽,使用也比較簡單,推薦使用 Guava 這種方式生成不可變集合。

foreach 增加/刪除元素大坑

先來看一段代碼:

String[] arrays = {&34;, &34;, &34;};List<String> list = new ArrayList<>(Arrays.asList(arrays));for (String str : list) {    if (str.equals(&34;)) {        list.remove(str);    }}

上面的代碼我們使用 foreach 方式遍歷 List 集合,如果符合條件,將會從集合中刪除改元素。

這個程序編譯正常,但是運行時,程序將會發生異常,日誌如下:

java.util.ConcurrentModificationException at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:939) at java.base/java.util.ArrayList$Itr.next(ArrayList.java:893)

可以看到程序最終錯誤是由 ArrayList$Itr.next 處的代碼拋出,但是代碼中我們並沒有調用該方法,為什麼會這樣?

實際是因為 foreach 這種方式實際上 Java 給我們提供的一種語法糖,編譯之後將會變為另一種方式。

我們將上面的代碼產生 class 文件反編來看下最後代碼長的啥樣。

fanbainyi

可以看到 foreach 這種方式實際就是 Iterator 迭代器實現方式,這就是為什麼 foreach 被遍歷的類需要實現 Iterator接口的原因。

接著我們來看下拋出異常方法:

expectedModCount 來源於 listremove 之後將會使 modCount 加一,expectedModCount與 modCount 將會不相等,這就導致迭代器遍歷時將會拋錯。

modCount 計數操作將會交子類自己操作,ArrayList 每次修改操作(增、刪)都會使 modCount 加 1。但是如 CopyOnWriteArrayList 並不會使用 modCount 計數。

所以 CopyOnWriteArrayList 使用 foreach 刪除是安全的,但是還是建議使用如下兩種刪除元素,統一操作。

修復的辦法有兩種:

使用 IteratorremoveIf

推薦使用 JDK1.8 這種方式,簡潔明了。

思考

如果我將上面 foreach 代碼判斷條件簡單修改一下:

remove

運行這段代碼,可以發現這段代碼又不會報錯了,有沒有很意外?

感興趣的同學可以自行研究源碼,或者直接查看 @why技術的文章:

總結

第一,我們不要先入為主,想當然就認為 Arrays.asList 和 List.subList 就是一個普通,獨立的 ArrayList。

如果沒辦法,使用了 Arrays.asList 和 List.subList ,返回給其他方法的時候,一定要記得再套娃一層真正的 java.util.ArrayList。

第二 JDK 的提供的不可變集合實際非常笨重,並且低效,還不安全,所以推薦使用 Guava 不可變集合代替。

最後,切記,不要隨便在 foreach增加/刪除元素。

最後(求點讚,求關注)

你在 List 集合使用過程還踩過什麼坑,歡迎留言討論。

我是樓下小黑哥,我們下篇文章再見~

相關焦點

  • 一口氣帶你踩完五個 List 的大坑,處處坑!|原力計劃
    既然天天在用,那就沒準就會踩中這幾個 List 常見坑。今天我們就來總結這些常見的坑在哪裡,撈自己一手,防止後續同學再繼續踩坑。本文設計知識點如下:ArrayList 這是李逵,還是李鬼?以前實習的時候,寫過這樣一段簡單代碼,通過 Arrays#asList 將數組轉化為 List 集合。
  • 代寫論文每篇收費幾千塊,火爆生意的背後,有哪五個大坑?
    這年頭處處都有造假,讓人防不勝防。充斥著網絡的論文代寫生意,背後究竟有哪些坑?我們該怎麼認識這些坑?對於論文,我們究竟該如何對待?坑一:假冒團隊每一個所謂的論文代寫團隊,都會把自己的背景包裝得無比高大上。有的聲稱全部985碩博專業代寫團隊,有的聲稱給高價就能讓博士生、碩士生導師幫忙代寫。可現實是什麼呢?
  • 囟門=命門,護理的3大坑,踩了會出大事
    「啊啊啊我根本摸不到我娃的囟門啊!」冷靜!最貼心的人是誰?是科大大!今天,貼心科大大就要來給大家好好說一說囟門那些事兒!科大大先科普下囟門閉合的時間:前囟門:從寶寶5個月開始關閉,一般在2歲前關閉,大部分在1歲到1歲半之間關閉。後囟門:一般在出生後2~3個月就會閉合,最晚4個月閉合。娃的囟門閉合時間差異性非常大,早點晚點不用太擔心。
  • 網際網路的十大坑你知道嗎?你又踩過哪幾個坑呢?
    真可謂&34;,但你還束手無策,氣煞人也!下面這中國網際網路十大坑,你又踩過幾個呢?作惡的搜尋引擎說到網際網路時代的大坑,怎麼跑得了搜尋引擎。搜尋引擎曾經是全網流量入口的中心,正是因為這樣近乎壟斷的地位,也讓搜尋引擎對人們的傷害至深。除了廣告啥也搜不到,甚至為坑蒙拐騙打廣告,因此人們用&34;來形容這些網際網路巨頭,再貼切不過。
  • 這些保險的大坑和小套路千萬別踩!看完心裡有數!
    然而,不少真心想買保險的人卻發現自己在買保險的路上頻頻踩坑,而一旦踩坑,造成的損失會相當大。今天小編就來給大家排排雷,聊聊保險都有哪些坑和套路呢?一起來看看。坑一:萬能險真的「萬能」嗎?然而事實上,它確是一個大坑。萬能險一般有兩個帳戶:保障帳戶和理財帳戶,保障帳戶可以保障一些條款內的重疾、意外和附加的一些輕症。理財帳戶則會承諾你到期返還本金,還有最低收益。聽起來好像很完美,然而,讓我們來看看萬能險的保障功能:保障的項目雖然多,但是單個項目賠付的錢卻很少。
  • 這些 Java 8 官方挖的坑,你踩過幾個?
    Stream很高大上,List轉Map卻全失敗……這些JDK8官方挖的坑,你踩過幾個?1582-10-15和1582-10-04你覺得會相隔幾天呢?11天還是1天?有興趣的小夥伴自己去寫個代碼試試吧。天真,不報個錯你怎麼能意識到JDK存在呢。
  • 小心別踩這些坑!
    網購家具真便宜,足不出戶價比三家網上買家具是真的便宜,而且商家店鋪多,方便在線價比三家,一件家具省一點,整體下來就能節省一大筆。網購家具包安裝,省時省力兩不誤網上的家具服務也是非常到位的,小編一年前買的電視櫃,廠家不僅免費上門安裝,還送了2年的免費質保,真是省時省力更省心,當然一定要選擇大品牌哦~說了這麼多網購家具的優勢,接下來咱們也得說說網購家具存在哪些弊端,千萬要小心,避免踩坑!
  • 安裝窗簾水太深,這5個大坑讓我多花上千元,看完後別再被套路!
    導讀:安裝窗簾水太深,這5個大坑讓我多花上千元,看完後別再被套路!買了新房後雖然會讓人覺得很幸福,但隨之而來的裝修問題還是會讓我們感到頭疼的,畢竟裝修需要我們付出金錢、精力和時間,特別是和各種材料商「鬥智鬥勇」的時候,會讓我們感到十分頭疼,就怕自己一不小心就會被坑,而且裝修的水很深,一旦被坑,那麼就不是一點小錢的問題了。
  • 直播帶貨處處是「坑」 商家為何還搶著賠錢賺吆喝?
    「5月5日晚上10點開始,直播剛過15分鐘,備貨的1萬個西瓜就銷售一空。我們產品質量和價格一直很穩定,9斤以上的西瓜在門店賣70元一個,『五五購物節』期間上海55元一個包郵,因為低價一下子就火了。」何明芳說。  雖然銷量大幅提高,但上海桃詠卻沒有從直播帶貨中賺到錢。
  • 裝修大坑!90%家庭訂木門選象牙白色翻車了,裝完才知道這麼黃
    大家之所以會選擇象牙白色,有的是因為刷了白牆,怕家裡看起來一片死白;還有些業主是為了看起來與眾不同,最後出來的效果都被自己的選擇氣哭,可以直接說這是一個裝修大坑,被它的名字給騙到了!裝修為什麼不要選擇象牙白色?象牙白其實是一種比較舒適的顏色,對人的視覺神經非常友好。
  • 華為踩大坑?麒麟晶片意外翻車?國人:被臺積電坑了
    華為踩大坑國人:被臺積電坑了!眾所周知,華為5G技術的發展已經遠超世界各國,甚至連美國都將華為作為5G技術的最大競爭對手,為了避免華為威脅自己的地位,美國不斷對華為實施各種打壓措施。最重要的是,麒麟9000晶片受美國晶片禁令影響,對華為的供應並不是非常充足,而Mate400也很可能成為華為麒麟晶片的最後一代手機,但在上市之後,卻有人表示華為臺積電坑了。
  • 動漫新坑:動漫那些年,我踩過的坑,動漫作品推薦
    但是,坦白來講,這3部的坑可以跳, 因為,《機器貓》的結局其實早已註定,因為,在劇情中不止一次暗示,在機器貓的幫助下,大雄最終和暗戀的小靜結婚了(啊啊,這部有電影證實啊),因為IP價值大,後續的電影繼續出吧。同理還有《蠟筆小新》,因為日常的劇情容易編劇,同樣在繼續出電影,至於《櫻桃小丸子》,類似小新同學,你說說它的主線是什麼?所以,這些坑跳了沒事,一個翻身就出來了。
  • Java 的這 100 個坑,我發誓不會再踩了
    所以,他從自己接觸過的 200+ 真實生產事件和事故中,整理出 100 個 Demo,涉及 130 個坑點和 50 個最佳實踐,都在這個專欄裡。,結合代碼演示,帶你掌握規避高頻坑點的方法,真正提升解決問題的能力。
  • 裝修不踩坑,廚房裝修這5大坑你踩了嗎?
    一不小心就容易踩坑,裝修得不實用。1. 櫥櫃檯面高度不合適櫥櫃一般都是按照普遍的高度統一定製的,但其實每個人身高不同,應該要因人而異,適合的高度才能讓做飯的人更舒適更輕鬆,否則臺面太低就要彎腰,臺面太高又要抬著手臂幹活,都非常不舒服,所以定製臺面高度的時候要提前量好身高和尺寸,以定製出最合適的高度。
  • 看看你中招沒?中國網際網路的十個大坑
    更不能忍的是,網際網路上的這些「大坑」都是商家為了利益而故意為之。真可謂「輕則謀財,重則害命」,但你還束手無策,氣煞人也!下面這中國網際網路十大坑,你又踩過幾個呢?中國網際網路十大坑,你又踩過幾個?快速爆炒,刷粉刷量,瘋狂帶貨,銷聲匿跡。流水般的網紅,鐵打的殺豬盤,跟網紅沾邊的,很少有不挨坑的。
  • 想報班獨立站培訓,如何避免踩坑
    一招教你避坑:選擇理論和實操都具備的培訓公司和大家想的一樣,肯定就是去報班了,市場上做跨境電商培訓的機構也挺多,當時怕踩坑,就分析了一波,覺得有幾個公司也還不錯,實地考察溝通後選擇了一家自己認為可以的培訓機構,交錢培訓後才發現他們只講理論,沒有實際運營經驗,指導的老師也沒有做過獨立站,學員們沒法得到更多的指導學習。就這樣被坑了!錢也交了,東西卻沒學到!
  • 米拾唐揭秘購買養生壺6個大坑之五價格篇
    米拾唐揭秘購買養生壺的6個大坑之五價格篇玻璃養生壺哪個品牌好?如何去購買養生壺?在這裡從事小家電開發與製造多年的米拾唐(Mr Tang)將為大家揭秘購買養生壺必須繞過的6個大坑,從這6個維度去了解了玻璃養生壺產品,就會知道如何正確購買玻璃養生壺。
  • 亞馬遜侵權坑丨怎麼避免踩坑,踩坑了怎麼辦?(含申訴郵件模板)
    亞馬遜賣家在通往爆單的路上,總會遇到大大小小的坑,踩進小坑還好說,就當是積累經驗,但踩到大坑就慘了,分分鐘致命。重點是,這個坑可能是隱形的!店鋪都被封完了,很多賣家尤其是新手賣家還不知道自己踩了這個侵權坑。
  • 盤點那些年踩過的母嬰用品的坑!踩坑率高達80%,寶媽含淚分享!
    功課做了無數,坑也踩了無數...說得就是我吧!!!今天決定說說我那些年翻車的母嬰用品,姐妹們記得避雷!別再步我的後塵了!我真的是要吐血了,好吧,我娃反而不適合這款,讓給姨姨用吧4.咬咬樂看起來是寶寶磨牙好工具,但是呢...果蔬裝進去都困難,寶寶吸起來費勁,還吃不乾淨弄得亂七八糟的...最後遭殃的還是我!最終成了個玩具,還不如吃磨牙餅乾呢。
  • Shopping list是購物清單,那「bucket list」是啥?相信你也有!
    最近咔咔被小夥伴的各種list洗腦!特別是李佳琪的口紅推薦list清單!看完這個口紅購買清單,只能發出「蒼天啊!大地啊!錢包啊!」的感嘆了!那今天我就來跟風總結一下各種各樣的list(清單)。1.What’s next on the shopping list?好的,我們有蘋果,麵包和牛奶了。購物清單上下一個要買的是啥?好了,現在你知道Shopping list是購物清單,那「bucket list」是啥?相信你也有!2. Bucket listBucket是水桶,list是清單,可「bucket list」不是水桶清單吶!