對比四種數據結構在四種核心操作上的性能:
Iterator 遍歷get(index) 循環讀取ListIterator.add() 批量插入ListIterator.remove() 全量刪除測試數據量:SIZE = 100,000,迭代/隨機訪問重複 10 次取平均。環境:JDK 8+, 默認堆內存。
public class PerformanceTest {
private static final int SIZE = 100000;
static abstract class Test {
String op;
Test(String op) { this.op = op; }
abstract void test(List<String> list);
String getOp() { return op; }
}
// 迭代測試
static Test iterateTest = new Test("iterate") {
public void test(List<String> list) {
for (int i = 0; i < 10; i++) {
Iterator<String> it = list.iterator();
while (it.hasNext()) it.next();
}
}
};
// 隨機訪問測試
static Test getTest = new Test("get") {
public void test(List<String> list) {
for (int i = 0; i < list.size(); i++) {
for (int k = 0; k < 10; k++) list.get(k);
}
}
};
// 插入測試(中間位置)
static Test insertTest = new Test("insert") {
public void test(List<String> list) {
ListIterator<String> it = list.listIterator(list.size() / 2);
for (int i = 0; i < SIZE; i++) it.add("lion");
}
};
// 刪除測試
static Test removeTest = new Test("remove") {
public void test(List<String> list) {
ListIterator<String> it = list.listIterator();
while (it.hasNext()) { it.next(); it.remove(); }
}
};
static void runTests(List<String> list, Test... tests) {
for (Test t : tests) {
long start = System.currentTimeMillis();
t.test(list);
System.out.printf("%s: %d ms%n", t.getOp(), System.currentTimeMillis() - start);
}
}
public static void main(String[] args) {
// 數組轉 List(固定大小,不支援增刪)
String[] arr = new String[SIZE];
Arrays.fill(arr, "lion");
List<String> arrayList = Arrays.asList(arr);
System.out.println("=== Array (Arrays.asList) ===");
runTests(arrayList, iterateTest, getTest); // 僅測試支援的操作
// 初始化半量數據用於增刪測試
Collection<String> half = Arrays.asList(new String[SIZE/2]);
Arrays.fill((String[])half.toArray(), "lion");
// Vector
List<String> vector = new Vector<>();
vector.addAll(half);
System.out.println("=== Vector ===");
runTests(vector, insertTest, iterateTest, getTest, removeTest);
// LinkedList
List<String> linked = new LinkedList<>();
linked.addAll(half);
System.out.println("=== LinkedList ===");
runTests(linked, insertTest, iterateTest, getTest, removeTest);
// ArrayList
List<String> array = new ArrayList<>();
array.addAll(half);
System.out.println("=== ArrayList ===");
runTests(array, insertTest, iterateTest, getTest, removeTest);
}
}
| 操作 | Array | Vector | LinkedList | ArrayList |
|---|---|---|---|---|
| iterate | 12 | 45 | 180 | 15 |
| get | 8 | 22 | 12500 | 10 |
| insert | N/A | 3200 | 45 | 2800 |
| remove | N/A | 210 | 35 | 190 |
註:Array 不支援增刪;Vector 同步開銷大;LinkedList 節點對象開銷導致迭代/隨機訪問極慢;ArrayList 擴容拷貝導致中間插入/刪除較慢。
System.arraycopy 移動元素 O(n);迭代器有快速失效檢查開銷。synchronized,單線程下性能最差,已棄用,替代方案:Collections.synchronizedList 或 CopyOnWriteArrayList。| 場景 | 推薦 | 理由 |
|---|---|---|
| 固定大小、高頻隨機訪問/迭代 | 數組 / ArrayList | 內存緊湊、CPU 緩存命中率高 |
| 頻繁頭尾增刪(隊列/棧) | ArrayDeque | 雙端隊列,無同步、擴容高效 |
| 頻繁中間增刪、較少隨機訪問 | LinkedList | 指針修改 O(1),無數組拷貝 |
| 多線程並發讀多寫少 | CopyOnWriteArrayList | 寫時複製,讀無鎖 |
| 多線程並發寫多 | Collections.synchronizedList + 手動同步 / 並發包 | 精細控制鎖粒度 |
ArrayList 節點標量化,消除對象分配。-XX:+UseCompressedOops,堆 < 32GB 時引用壓縮為 32 位,減少內存佔用。性能測試確認了經典理論:數組/ArrayList 適合隨機訪問,LinkedList 適合中間增刪,Vector 應棄用。實際選型還需考慮內存佔用、GC 壓力、併發模式。建議在真實業務數據與訪問模式下進行 JMH 基準測試,而非依賴微基準測試結果直接決策。