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

Java 集合框架精髓:HashSet 與 ArrayList 異同深度解析與去重實戰

     編輯:Java 綜合教學

核心定義對比

特性ArrayList (List)HashSet (Set)
有序性有序:按添加順序維護索引位置無序:基於哈希值分佈,迭代順序不固定
重復性可重復:equals() 為 true 也可共存不可重復:equals() 為 true 視為同一元素
底層結構動態數組 Object[] elementDataHashMap map(Key 存元素,Value 固定 PRESENT)
隨機訪問O(1) get(index)不支持索引訪問
查找/插入/刪除O(n) 線性掃描O(1) 平均(依賴 hashCode 分佈均勻)
空元素允許任意多個 null允許一個 null

直觀代碼驗證

List<Integer> list = new ArrayList<>();
Set<Integer> set = new HashSet<>();
Arrays.asList(1,2,0,3,2,1,3,5,0).forEach(n -> { list.add(n); set.add(n); });

System.out.println("ArrayList: " + list); // [1, 2, 0, 3, 2, 1, 3, 5, 0] 保留順序與重復
System.out.println("HashSet:   " + set);   // [0, 1, 2, 3, 5]       去重、無序

ArrayList vs HashSet 輸出對比

關鍵點:Integer 重寫了 equals/hashCode

所以 new Integer(1).equals(new Integer(1)) == true,HashSet 能正確去重。自定義類若未重寫 equals/hashCode,HashSet 將按引用地址判斷,失去去重功能。

實戰:List 去重保留順序

方案一:LinkedHashSet(最簡潔,Java 8+ 推薦)

List<Integer> distinct = new ArrayList<>(new LinkedHashSet<>(list));
  • LinkedHashSet 維護雙向鏈表記錄插入順序,同時具備 Set 去重特性
  • 一行代碼完成「去重 + 保序 + 轉 List」

方案二:手動迭代 + HashSet 輔助(理解原理)

public static void rmRepeatedElementByOrder(List<Integer> list) {
    Set<Integer> seen = new HashSet<>();
    List<Integer> result = new ArrayList<>();
    for (Integer e : list) {
        if (seen.add(e)) { // add 返回 true 表示首次見到
            result.add(e);
        }
    }
    list.clear();
    list.addAll(result);
}
  • 時間 O(n),空間 O(n)
  • 適用於無法引入 LinkedHashSet 的老版本環境

方案三:Stream API(Java 8+ 函數式風格)

List<Integer> distinct = list.stream().distinct().collect(Collectors.toList());
  • 內部實現同 LinkedHashSet,語義更清晰
  • 並行流 parallelStream() 去重結果順序不保證

性能選型指南

場景推薦集合理由
頻繁隨機訪問、末尾增刪ArrayList數組結構,緩存友好
頻繁頭部/中間增刪LinkedList鏈表結構,無需數組擴容/位移
高頻查找、去重、集合運算HashSet哈希表 O(1) 查找
去重且需保持插入順序LinkedHashSet哈希+雙向鏈表
有序集合、範圍查詢TreeSet紅黑樹,自然序/比較器序
多線程環境CopyOnWriteArrayList / ConcurrentHashMap.keySet()線程安全讀多寫少 / 高並發

避坑提醒

  1. 自定義對象進 Set/Map Key 必須重寫 equals/hashCode,且保持一致性契約。
  2. ArrayList.remove(Object) 遍歷刪除易導致 ConcurrentModificationException,請用 Iterator.remove() 或反向循環。
  3. HashSet 非線程安全,多線程請用 Collections.synchronizedSet() 或 ConcurrentHashMap.newKeySet()。
  4. 大數據量去重考慮 Bloom Filter(布隆過濾器)預過濾,減少內存壓力。

集合選型無銀彈,理解底層數據結構與複雜度,根據業務訪問模式決策,才是架構師思維。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved