天天看點

慎用ArrayList的contains方法,使用HashSet的contains方法代替

在啟動一個應用的時候,發現其中有一處資料加載要數分鐘,剛開始以為是需要load的資料比較多的緣故,查了一下資料庫有6條左右,但是單獨寫了一個資料讀取的方法,将這6萬多條全部讀過來,卻隻需要不到10秒鐘,就覺得這裡面肯定有問題,于是仔細看其中的邏輯,其中有一段資料去重的邏輯,就是記錄中存在某幾個字段相同的,就認為是重複資料,就需要将重複資料給過濾掉。這裡就用到了一個List來存放這幾個字段所組成的主鍵,如果發現相同的就不處理,代碼無非就是下面這樣:

[java]  view plain  copy

  1. List<string> uniqueKeyList = new ArrayList<string>();  
  2. //......  
  3. if (uniqueKeyList.contains(uniqueKey)) {  
  4.                     continue;  
  5.                 }  
  6. </string></string>  

根據鍵去查找是不是已經存在了,來判斷是否重複資料。經過分析,這一塊耗費了非常多的時候,于是就去檢視ArrayList的contains方法的源碼,發現其最終會調用他本身的indexOf方法:

[java]  view plain  copy

  1. public int indexOf(Object elem) {  
  2.     if (elem == null) {  
  3.         for (int i = 0; i < size; i++)  
  4.         if (elementData[i]==null)  
  5.             return i;  
  6.     } else {  
  7.         for (int i = 0; i < size; i++)  
  8.         if (elem.equals(elementData[i]))  
  9.             return i;  
  10.     }  
  11.     return -1;  
  12.     }  

原來在這裡他做的是周遊整個list進行查找,最多可能對一個鍵的查找會達到6萬多次,也就是會掃描整個List,驗怪會這麼慢了。

于是将原來的List替換為Set:

[java]  view plain  copy

  1. Set<string> uniqueKeySet = new HashSet<string>();  
  2. //......  
  3. if (uniqueKeySet.contains(uniqueKey)) {  
  4.                     continue;  
  5.                 }  

速度一下就上去了,在去重這一塊最多花費了一秒鐘,為什麼HashSet的速度一下就上去了,那是因為其内部使用的是Hashtable,這是HashSet的contains的源碼:

[java]  view plain  copy

  1. public boolean contains(Object o) {  
  2.     return map.containsKey(o);  
  3.     }  

如果不知道為什麼使用Hash就變快了,可以看一下我的另外一篇文章: Java中hashCode的作用