首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 集合去重完全指南:List 與 Set 互轉、equals/hashCode 契約與性能基準測試

     編輯:Java 相關知識

去重核心思路:利用 Set 無序唯一特性

// 通用去重:不保留順序
public static  void removeDuplicates(Collection collection) {
    Set set = new HashSet<>(collection);
    collection.clear();
    collection.addAll(set);
}

// 保留順序去重:LinkedHashSet
public static  List distinctPreserveOrder(List list) {
    return new ArrayList<>(new LinkedHashSet<>(list));
}

自定義對象去重陷阱:必須重寫 equals/hashCode

public class Person {
    private int id;
    private String name;
    
    // 構造器、getter/setter 省略
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return id == person.id && Objects.equals(name, person.name);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(id, name); // JDK 7+ 推薦
    }
}

HashSet 去重原理:

  1. 計算元素 hashCode() 確定桶位置
  2. 遍歷桶中鏈表/紅黑樹,調用 equals() 比較
  3. 兩者均相等視為重複,不添加

契約:equals() 相等 ⇒ hashCode() 必相等;hashCode() 相等 ⇏ equals() 相等(哈希碰撞)。

HashMap/HashSet 源碼關鍵邏輯

// HashMap.putVal 核心判斷
if (e.hash == hash && (e.key == key || key.equals(e.key))) {
    // 找到重複 key,替換 value
}

// HashSet.add 內部調用 map.put(e, PRESENT)
public boolean add(E e) {
    return map.put(e, PRESENT) == null;
}

性能基準測試:10000 隨機 Person 對象

方法耗時(ms)比較次數複雜度說明
HashSet 去重263,653O(n)哈希分桶,極少比較
雙重循環對比37828,463,252O(n²)全量遍歷比較,隨數據增長急劇惡化
// 低效寫法:O(n²)
public static void inefficientRemove(Person[] arr) {
    Person[] result = new Person[arr.length];
    int idx = 0;
    for (int i = 0; i < arr.length; i++) {
        boolean dup = false;
        for (int j = 0; j < idx; j++) {
            if (arr[i].equals(result[j])) { dup = true; break; }
        }
        if (!dup) result[idx++] = arr[i];
    }
}

數組與 List 互轉最佳實踐

// 數組 → List(固定長度,不可增刪)
String[] arr = {"a", "b", "c"};
List list = Arrays.asList(arr); // 返回 Arrays$ArrayList,非 ArrayList
List mutableList = new ArrayList<>(Arrays.asList(arr)); // 可變副本

// List → 數組
List list = new ArrayList<>();
list.add("x");
String[] toArray = list.toArray(new String[0]); // JDK 11+ 推薦 new String[0]

// 基本類型數組無法直接轉 List,需流式處理
int[] ints = {1,2,3};
List intList = Arrays.stream(ints).boxed().collect(Collectors.toList());

進階去重場景

  • 按屬性去重:list.stream().collect(Collectors.toMap(Person::getId, p -> p, (a,b) -> a)).values()
  • 大數據流式去重:Bloom Filter(布隆過濾器)預過濾 + 精確去重
  • 並發環境:ConcurrentHashMap.newKeySet() 或 Collections.synchronizedSet
  • 自定義比較器:TreeSet<>(Comparator.comparing(Person::getId)) 保序去重
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved