針對 ArrayList 移除重複元素,提供三種不同效能與適用場景的寫法,並說明底層原理與選型建議。
List<String> list = Arrays.asList(
"java03", "java03", "java01", "java02", "java01", "java02", "java01"
);
// 預期結果:[java03, java01, java02] (保留首次出現順序)
public static <T> List<T> distinctWithIterator(List<T> src) {
List<T> result = new ArrayList<>();
for (Iterator<T> it = src.iterator(); it.hasNext(); ) {
T elem = it.next();
if (!result.contains(elem)) result.add(elem); // O(n) 查找
}
return result;
}
// 時間複雜度:O(n²) — 適合小資料量 ( < 1000 )
public static <T> List<T> distinctWithLinkedHashSet(List<T> src) {
return new ArrayList<>(new LinkedHashSet<>(src));
}
// LinkedHashSet 內部雜湊表 + 雙向鏈表,同時保證唯一性與插入順序
// 時間複雜度:O(n) — **通用首選**
public static <T> List<T> distinctWithStream(List<T> src) {
return src.stream().distinct().collect(Collectors.toList());
}
// 底層同 LinkedHashSet,語意更清晰,支援 parallelStream() 大資料並行去重
Iterator+List : ~1,200 ms (O(n²) 明顯劣勢)
LinkedHashSet : ~15 ms
Stream.distinct() : ~18 ms
// 例:User 物件以 id 去重
List<User> users = ...;
List<User> unique = users.stream()
.collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(User::getId))),
ArrayList::new
));
// 或使用 Map 去重 (保留首次/最後出現)
Map<Long, User> map = users.stream()
.collect(Collectors.toMap(User::getId, u -> u, (v1, v2) -> v1)); // 保留首次
List<User> unique2 = new ArrayList<>(map.values());
| 場景 | 推薦寫法 | 理由 |
|---|---|---|
| 一般業務 List 去重 (保留順序) | new ArrayList<>(new LinkedHashSet<>(list)) | 簡潔、O(n)、無額外依賴 |
| JDK 8+ 專案、偏好函數風格 | list.stream().distinct().collect(toList()) | 語意明確、易並行化 |
| 極小資料量 (<100)、避免建立額外集合 | 迭代器手寫 | 零額外物件分配 |
| 依據特定屬性去重 | Stream + toMap / TreeSet + Comparator | 靈活控制比較邏輯 |
| 高併發環境、共享 List | CopyOnWriteArrayList + 上述任一 | 執行緒安全快照 |
import java.util.*;
class ArrayListDistinct {
public static void main(String[] args) {
ArrayList<String> al = new ArrayList<>(Arrays.asList(
"java03", "java03", "java01", "java02", "java01", "java02", "java01"
));
System.out.println("去重前: " + al);
ArrayList<String> result = distinct(al);
System.out.println("去重後: " + result);
}
static ArrayList<String> distinct(ArrayList<String> src) {
ArrayList<String> newAl = new ArrayList<>();
Iterator<String> it = src.iterator();
while (it.hasNext()) {
String obj = it.next();
if (!newAl.contains(obj)) newAl.add(obj);
}
return newAl;
}
}