JavaRush /Java Blog /Random-TW /關於 Java 集合的十大問題
FedoraLinux
等級 21
Москва

關於 Java 集合的十大問題

在 Random-TW 群組發布
本文是關於 Java 集合的十大問題一文的翻譯。以下是 Stackowerflow 上有關 Java 集合最常見的問題。在看這些問題之前,最好先看一下類別層次結構圖。 1.什麼時候使用LinkedList代替ArrayList? ArrayList實際上是一個陣列;它的元素可以透過索引直接存取。如果數組溢出,則需要一個具有更多空間的新數組。放置和移動所有元素將花費 O(n) 時間。此外,新增和刪除元素對於移動數組中的現有元素是必要的。這也許是使用ArrayList最大的不便。LinkedList 是元素連結的雙重清單。因此,要存取中心的元素,您必須從工作表的開頭到結尾進行搜尋。另一方面,在 LinkedList 中新增和刪除元素速度更快,因為這些操作只會變更清單本身。最糟糕的時間比較如下:
方法 數組列表 鍊錶
取得(索引) 複雜度(1) 在)
添加(E) 在) 複雜度(1)
新增(E,索引) 在) 在)
刪除(索引) 在) 在)
迭代器.remove() 在) 複雜度(1)
迭代器.add(E) 在) 複雜度(1)
儘管運行時間較長,但對於大型列表,必須單獨考慮記憶體使用情況。在 LinkedList 中,每個節點必須至少有兩個額外的指標來連結前一個和下一個節點,而在 ArrayList 中,只需要一個元素陣列。更多ArrayList、LinkedList和Vector 清單的比較。 2. 在集合迭代期間刪除元素的高效等效方法 在迭代期間修改(刪除元素)集合的唯一正確方法是使用 Iterator.remove()。例如: 最常見的錯誤是: 執行上面的程式碼時, 您將收到 ConcurrentModificationException 。發生這種情況是因為生成迭代器是為了在整個列表中移動,但同時透過呼叫 Iterator.remove() 來更改了工作表。正如該異常的文檔中所寫, Iterator itr = list.iterator(); while(itr.hasNext()) { // do something itr.remove(); } for(Integer i: list) { list.remove(i); }
“通常不允許一個線程修改集合,而另一個線程正在迭代它。”
一般來說,一個線程修改集合而另一個線程正在遍歷它是不可接受的。 3. 如何將List轉換為int[]陣列? 最簡單的方法是使用位於 Apache Commons Lang庫中的 ArrayUtils。 JDK 中沒有此表達式的捷徑。請記住,您不能使用 List.toArray(),因為此表達式將 List 轉換為 Integer[](這 不是基本類型)。正確的做法是以下選項: 4. 如何將 int[] 陣列轉換為 List? 最簡單的方法也是使用 Apache Commons Lang庫中的 ArrayUtils,如上所述。 另外,JDK 中沒有此表達式的捷徑。 5. 過濾集合的最佳方式是什麼? 您可以使用第三方軟體包(例如 GuavaApache Commons Lang)來增加功能。這兩個套件都有一個filter()方法(在Guava的 Collections2類別和Apache的 CollectionUtils中)。filter() 方法將傳回與給定謂詞相符的元素。在 JDK 中,一切都更加複雜。好消息是 Java 8 中將添加謂詞 但現在您需要使用 Iterator 來迭代整個集合。 當然,您可以透過熟悉新的 Predicate 介面來模仿 Guava 和 Apache 所遵循的路徑。 現在我們可以使用下面的程式碼來過濾集合: 6. 如何輕鬆地將List轉換為Set? 有兩種方法可以做到這一點,具體取決於您想要如何定義平等。第一段程式碼將清單放入 HashSet 中。這種情況下的重複主要是透過hashCode()來確定的。通常這會起作用。但如果您需要考慮比較路徑,那麼最好使用程式碼的第二部分,您可以在其中定義自己的比較器。 7. 如何從ArrayList中刪除重複元素? 這個問題和上面的問題有些關聯。如果 ArrayList 中元素的順序對您來說並不重要,那麼明智的做法是將工作表放入 Set 中以刪除重複項,然後將其傳回 List。下面是一個例子。 如果元素的順序對您很重要,那麼可以透過將清單放置在標準 JDK 中的 LinkedHashSet中來確保順序。 8. 排序集合 int[] array = ArrayUtils.toPrimitive(list.toArray(new Integer[0])); int[] array = new int[list.size()]; for(int i=0; i < list.size(); i++) { array[i] = list.get(i); } List list = Arrays.asList(ArrayUtils.toObject(array)); int[] array = {1,2,3,4,5}; List list = new ArrayList (); for(int i: array) { list.add(i); } Iterator itr = list.iterator(); while(itr.hasNext()) { int i = itr.next(); if (i > 5) { // filter all ints bigger than 5 itr.remove(); } } public interface Predicate { boolean test(T o); } public static void filter(Collection collection, Predicate predicate) { if ((collection != null) && (predicate != null)) { Iterator itr = collection.iterator(); while(itr.hasNext()) { T obj = itr.next(); if (!predicate.test(obj)) { itr.remove(); } } } } filter(list, new Predicate () { public boolean test(Integer i) { return i <= 5; } }); Set set = new HashSet (list); Set set = new TreeSet (aComparator); set.addAll(list); ArrayList** list = ... // initial a list with duplicate elements Set set = new HashSet (list); list.clear(); list.addAll(set); Java 中支援排序集合的方法有多種。它們都按自然順序或按指定的比較器提供集合。在自然順序的情況下,還需要在元素上 實作 Comparable介面。
  1. Collections.sort()可以對List進行排序。正如 Java 文件中所述,這種排序是穩定的並保證 n log(n) 效能。
  2. PriorityQueue提供了一個有順序的佇列。PriorityQueue 和 Collections.sort() 的差異在於,PriorityQueue 總是保持佇列的順序,但只能取得佇列的第一個元素。您不能隨機存取像 PriorityQueue.get(4) 這樣的元素。
  3. 如果集合中沒有重複項,您可以選擇TreeSet。與 PriorityQueue 一樣,TreeSet 始終維護有序集。您可以從 TreeSet 中取得最小或最大的元素,但仍然無法隨機存取這些元素。
簡單地說,Collections.sort() 提供了一個一次性排序清單。PriorityQueue 和 TreeSet 始終維護有序集合,但代價是缺乏對元素的索引存取。 9. Collections.emptyList() 或新實例 同樣的問題也適用於emptyMap() 和emptySet()。兩種方法都會傳回一個空列表,但 Collections.emptyList() 是一個不可變列表。這意味著您 無法將新元素新增到“空”清單中。在後台,每次呼叫 Collections.emptyList() 方法實際上並不會建立空列表的新實例。相反,它將重複使用已經存在的空實例。如果您熟悉 Singleton作為一種 設計模式,您應該明白其含義。如果頻繁調用, 這應該會為您帶來 更好的性能。 10 複製集合,Collections.copy() 有兩種方法可以將來源清單複製到目標清單。一種方法是使用 ArrayList 建構子。 另一種方法是使用 Collections.copy()方法。注意第一行:我們分配的列表至少與原始列表的長度一樣長,因為關於集合的 Java 文件說: ArrayList dstList = new ArrayList (srcList);
目標清單必須至少與來源清單一樣長。
這意味著最終列表不得短於原始列表。 這兩種方法都是淺複製。那麼這兩種方法有什麼差別呢?首先,Collections.copy() 不會重新分配 dstList 集合的容量,即使 dstList 沒有足夠的空間來包含 srcList 中的所有元素。相反,它會拋出 IndexOutOfBoundsException。有人可能會問這樣做有什麼好處嗎?原因是這確保了該方法在時間上線性運行。當您想要重複使用陣列而不是在 ArrayList 建構函式中重新指派記憶體時,這也適用。 而不是結論 如果讀完文章後您仍然有疑問,請隨時在評論中提問。另外,如果您發現翻譯有任何不準確或任何其他錯誤,請寫信給PM,我們會更正,我們將感謝您。 原來的。 ArrayList dstList = new ArrayList (srcList.size()); Collections.copy(dstList, srcList);
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION