假設需求:從控制台讀取一行字符串,統計每個字符出現的次數。這是一個經典的「去重 + 計數」場景,恰好能串起 List、Set、Map 三大集合的核心特性。
public class CharFrequencyCounter {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("請輸入字符串: ");
String input = scanner.nextLine();
scanner.close();
// 1. List 保持順序、允許重複 —— 存儲所有字符(含重複)
List<Character> charList = new ArrayList<>();
for (char c : input.toCharArray()) {
charList.add(c);
}
// 2. Set 自動去重、無序 —— 獲取唯一字符集合
Set<Character> uniqueChars = new LinkedHashSet<>(charList); // 保持首次出現順序
// 3. Map 鍵值映射 —— 字符 -> 出現次數
Map<Character, Integer> frequencyMap = new LinkedHashMap<>();
for (Character c : uniqueChars) {
int count = Collections.frequency(charList, c); // O(n) 但代碼簡潔
frequencyMap.put(c, count);
}
// 輸出結果
frequencyMap.forEach((k, v) -> System.out.println(k + " 出現 " + v + " 次"));
}
}
| 特性 | List | Set | Map |
|---|---|---|---|
| 是否允許重複 | 是 | 否 | Key 不重複,Value 可重複 |
| 是否有序 | 按插入序有序 | HashSet 無序 LinkedHashSet 插入序 TreeSet 自然序/定制序 | HashMap 無序 LinkedHashMap 插入序/訪問序 TreeMap 自然序/定制序 |
| 核心實現類 | ArrayList、LinkedList、Vector | HashSet、LinkedHashSet、TreeSet | HashMap、LinkedHashMap、TreeMap、Hashtable |
| 線程安全 | Vector、Collections.synchronizedList | Collections.synchronizedSet | Hashtable、Collections.synchronizedMap、ConcurrentHashMap |
| 典型場景 | 有序數據、按索引訪問、允許重複 | 去重、集合運算(交/並/差)、唯一性約束 | 鍵值查找、緩存、分組統計、對象映射 |
Collections.synchronizedList 或 CopyOnWriteArrayList 替代。hashCode() & (n-1) 定位桶位置。
需要鍵值映射? ──Yes──► Map
├─ 需保持插入序? ──Yes──► LinkedHashMap
├─ 需按 Key 排序? ──Yes──► TreeMap
├─ 高併發寫入? ──Yes──► ConcurrentHashMap
└─ 一般場景 ──► HashMap
不需要鍵值映射?
├─ 需去重?
│ ├─ 需保持插入序? ──Yes──► LinkedHashSet
│ ├─ 需排序? ──Yes──► TreeSet
│ └─ 一般場景 ──► HashSet
└─ 允許重複、需有序?
├─ 頻繁隨機訪問/末尾追加? ──Yes──► ArrayList
├─ 頻繁頭尾增刪/作為隊列? ──Yes──► LinkedList
└─ 多線程只讀/寫少? ──► CopyOnWriteArrayList
Iterator.remove() 或 ListIterator,或先收集待刪元素再批量移除。equals() 和 hashCode(),且保持一致性(相等對象 hashCode 必相等)。new ArrayList<>(estimatedSize)、new HashMap<>((int)(size/0.75)+1) 避免頻繁擴容。ConcurrentHashMap、CopyOnWriteArrayList),切勿用 Vector/Hashtable。List、Set、Map 構成了 Java 集合框架的基石。理解其底層數據結構(數組、鏈表、哈希表、紅黑樹)、線程安全模型、以及各實現類的性能邊界,是寫出高效、穩健代碼的前提。下次選型時,請先問自己三個問題:需不需要鍵值?允不允許重複?有沒有順序/排序/併發要求? 答案即指引。