以下整理自 StackOverflow 高頻問題,建議先閱讀《Java 集合框架接口與類層次結構圖》建立整體認知。
ArrayList:底層動態數組,get(index) O(1);擴容與插入/刪除需搬移元素,O(n)。
LinkedList:雙向鏈表,隨機訪問 O(n);插入/刪除只改指針,O(1)。
| 操作 | ArrayList | LinkedList | |-------------------|-----------|------------| | get(index) | O(1) | O(n) | | add(E) | O(n) | O(1) | | add(E, index) | O(n) | O(n) | | remove(index) | O(n) | O(n) | | Iterator.remove() | O(n) | O(1) | | Iterator.add(E) | O(n) | O(1) |
記憶體方面:LinkedList 每節點額外兩指針,ArrayList 僅需數組。大列表時 ArrayList 更省內存。詳細對比見《ArrayList vs LinkedList vs Vector》。
唯一正確方式:Iterator.remove()
Iterator<Integer> itr = list.iterator();
while (itr.hasNext()) {
// do something
itr.remove();
}
錯誤示範:for (Integer i : list) { list.remove(i); } → 拋 ConcurrentModificationException。原因:for-each 隱式生成迭代器,同時修改列表違反單線程迭代器修改規則。
Apache Commons Lang(推薦):
int[] array = ArrayUtils.toPrimitive(list.toArray(new Integer[0]));
純 JDK:
int[] array = new int[list.size()];
for (int i = 0; i < list.size(); i++) {
array[i] = list.get(i);
}
注意:List.toArray() 返回 Integer[],不可直接轉 int[]。
Apache Commons Lang:
List<Integer> list = Arrays.asList(ArrayUtils.toObject(array));
純 JDK:
List<Integer> list = new ArrayList<>(); for (int i : array) list.add(i);
第三方庫:Guava Collections2.filter()、Apache CollectionUtils.filter()。
JDK 8+:Predicate + Stream API。
JDK 7-:手動迭代器遍歷 + itr.remove()。
// 自定義 Predicate 模仿 Guava
public interface Predicate<T> { boolean test(T o); }
public static <T> void filter(Collection<T> c, Predicate<T> p) {
if (c != null && p != null) {
Iterator<T> itr = c.iterator();
while (itr.hasNext()) if (!p.test(itr.next())) itr.remove();
}
}
// 使用
filter(list, new Predicate<Integer>() {
public boolean test(Integer i) { return i <= 5; }
});
兩種語義:
hashCode()/equals() 去重,適用大多數場景Set<Integer> set = new HashSet<>(list); // 或 Set<Integer> set = new TreeSet<>(comparator); set.addAll(list);
不保留順序:
Set<Integer> set = new HashSet<>(list); list.clear(); list.addAll(set);
保留順序:用 LinkedHashSet 替換 HashSet。
Collections.sort(list):一次性排序,穩定 O(n log n),需元素實現 ComparablePriorityQueue:始終有序,但只能訪問隊頭/尾,不支援隨機訪問TreeSet:無重複 + 始終有序,同樣不支援隨機訪問選擇建議:一次性排序用 Collections.sort();持續維持有序且不需隨機訪問,用 PriorityQueue 或 TreeSet。
Collections.emptyList() 返回不可變單例空列表,頻繁調用不創建新對象,性能更優;new ArrayList() 每次創建新可變實例。同理適用於 emptyMap()、emptySet()。
// 方式一 ArrayList<Integer> dst = new ArrayList<>(src); // 方式二 ArrayList<Integer> dst = new ArrayList<>(src.size()); Collections.copy(dst, src);
區別:
Collections.copy():目標容量不足拋 IndexOutOfBoundsException,不擴容;參數僅限 ListArrayList(Collection):自動擴容;接受任意 Collection,更通用兩者均為淺拷貝。
原文鏈接:programcreek.com