歡迎光臨
每天分享高質量文章

關於 Java Collections 的幾個常見問題

(點擊上方公眾號,可快速關註)


來源:linbingdong ,

linbingdong.com/2017/01/07/Stack%20Overflow上關於Java%20Collections的幾個常見問題/

列舉幾個關於Java Collections的常見問題並給出答案。

1. 什麼時候用LinkedList,什麼時候用ArrayList?

ArrayList是使用陣列實現的list,本質上就是陣列。ArrayList中的元素可以通過索引隨機獲取一個元素。但是如果該陣列已滿,當添加新元素時需要分配一個新的陣列然後將原來陣列的元素移動過去,需要O(n)的時間複雜度。添加或刪除一個元素需要移動陣列中的其他元素。這是ArrayList最大的缺點。

LinkedList是一個雙向鏈表。因此,當需要獲取list中某個元素,需要從頭到尾遍歷list。另一方面,在鏈表中添加或刪除元素很快,只需要O(1)的時間複雜度。從空間上來說,在鏈表中一個節點需要兩個額外的指標來指向它的previous和next節點。

總結:

從時間複雜度來說,如果對list增加或刪除操作較多,優先用LinkedList;如果查詢操作較多,優先用ArrayList。

從空間複雜度來說,LinkedList會占用較多空間。

2. 如何邊遍歷邊移除Collection中的元素

邊遍歷邊修改Collection的唯一正確方式是使用Iterator.remove()方法,如下:

Iterator it = list.iterator();

while(it.hasNext()){

    // do something

    it.remove();

}

一種最常見的錯誤代碼如下:

for(Integer i : list){

    list.remove(i)

}

運行以上錯誤代碼會報ConcurrentModificationException異常。這是因為當使用foreach(for(Integer i : list))陳述句時,會自動生成一個iterator來遍歷該list,但同時該list正在被Iterator.remove()修改。在Java中,一般不允許一個執行緒在遍歷collection時另一個執行緒在修改它。

3. 如何將List轉化成int[]?

很多人可能認為只需用List.toArray()即可,其實不然。List.toArray()方法只可能得到Integer[],無法得到int[]。

最簡單的方法是使用Apache Commons Lang庫中的ArrayUtils。

int[] array = ArrayUtils.toPrimitive(list.toArray(new Integer[0]));

在JDK中,沒有捷徑。需要註意的是,不能直接使用List.toArray(),因為這樣會將List轉化成Integer[]而不是int[]。正確的做法如下:

int[] array = new int

;

for(int i = 0; i < list.size(); i++){

    array[i] = list.get(i);

}

4. 如何將int[]轉化成List?

同上,很多人以為只需用Arrays.asList()即可,其實不然。因為不能以int[]作為該方法的引數,要的話也只能是Integer[]。

關於Arrays.asList()方法有如下特性:

  1. 該方法對於基本資料型別的陣列支持並不好,當陣列是基本資料型別時不建議使用

  2. 當使用asList()方法時,陣列就和串列鏈接在一起了。當更新其中之一時,另一個將自動獲得更新。因為asList獲得的List實際取用的就是陣列 註意:僅僅針對物件陣列型別,基本資料型別陣列不具備該特性。

  3. asList得到的陣列是的沒有add和remove方法的。因為asList傳回的List是Arrays中的內部類,而該類並沒有定義add和remove方法。

那麼如何將int[]轉化成List呢?

還是得自己實現:

int[] array = {1,2,3,4,5};

List list = new ArrayList();

for(int i: array) {

  list.add(i);

}

5. 過濾一個Collection最好的方法是什麼?

如過濾掉list中大於5的整數。

Iterator it = list.iterator();

while(it.hasNext()){

    int i = it.next();

    if(i > 5) {  //過濾掉大於5的整數

        it.remove(); 

    }

}

6. 將List轉化成Set最簡單的方法?

有兩種方法,取決於你怎麼要怎麼定義兩個元素相等。第一種方法是將list放入HashSet里,該方法元素是否相等是通過它們的hashCode()來比較的。如果需要自己定義比較的方法,需要用TreeSet。

Set set = new HashSet(list);

Set set = new TreeSet(aComparator);

set.addAll(list);

7. 如何刪除ArrayList中重覆的元素?

如果不關心元素在ArrayList中的順序,可以將list放入set中來刪除重覆元素,然後在放回list。

Set set = new HashSet(list);

list.clear();

list.addAll(set);

如果關心元素在ArrayList中的順序,可以用LinkedHashSet。

8. 有序的collection

Java里有很多方法來維持一個collection有序。有的需要實現Comparable接口,有的需要自己指定Comparator。

  1. Collections.sort()可以用來對list排序。該排序是穩定的,並且可以保證nlog(n)的性能。

  2. PriorityQueue提供排序的佇列。PriorityQueue和Collections.sort()的區別是,PriorityQueue動態維護一個有序的佇列(每添加或刪除一個元素就會重新排序),但是只能獲佇列中的頭元素。

  3. 如果collection中沒有重覆的元素,TreeSet是另一個選擇。跟PriorityQueue一樣的是,TreeSet也動態維護一個有序的集合。可以從TreeSet中獲取最大和最小的元素。

總結:Collections.sort()提供一個一次排序的list。PriorityQueue和TreeSet動態維護排序的collection。

9. 拷貝list

有兩種方法可以用來拷貝list。一種是使用ArrayList建構式。

ArrayList dstList = new ArrayList(srcList);

另一種是使用Collections.copy()。

ArrayList dstList = new ArrayList(srcList.size());

Collections.copy(dstList, srcList);

需要註意的是,使用該方法的話標的list至少跟源list長度一樣長。否則會報IndexOutOfBoundsException異常。

另外有兩點需要註意:

  1. 兩種方法都是淺拷貝

  2. Collections.copy()方法的兩個引數必須都是list,而ArrayList方法引數只要是collection即可,因此ArrayList方法更通用。

【關於投稿】


如果大家有原創好文投稿,請直接給公號發送留言。


① 留言格式:
【投稿】+《 文章標題》+ 文章鏈接

② 示例:
【投稿】《不要自稱是程式員,我十多年的 IT 職場總結》:http://blog.jobbole.com/94148/

③ 最後請附上您的個人簡介哈~



看完本文有收穫?請轉發分享給更多人

關註「ImportNew」,提升Java技能

赞(0)

分享創造快樂