Java 集合框架完全指南:从核心接口到 JDK 21 有序集合新特性

引言

集合是 Java 中最常用的数据结构容器,无论是存储对象、缓存数据还是传递参数,集合类无处不在。Java 集合框架(Java Collections Framework)提供了一套设计优良的接口和实现类,涵盖了列表、集合、队列、映射等各种数据结构。JDK 21 在集合方面带来了重要的增强------有序集合接口(Sequenced Collections),进一步统一了有序集合的访问方式。本文将系统介绍 Java 集合框架的核心接口、常用实现类、遍历方式以及 JDK 21 的新特性,帮助你全面掌握集合的使用。

下面是 Java 集合框架的整体架构图,帮助你建立全局认知:
#mermaid-svg-HCW5za5OlQVqs1EI{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-HCW5za5OlQVqs1EI .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-HCW5za5OlQVqs1EI .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-HCW5za5OlQVqs1EI .error-icon{fill:#552222;}#mermaid-svg-HCW5za5OlQVqs1EI .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-HCW5za5OlQVqs1EI .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-HCW5za5OlQVqs1EI .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-HCW5za5OlQVqs1EI .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-HCW5za5OlQVqs1EI .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-HCW5za5OlQVqs1EI .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-HCW5za5OlQVqs1EI .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-HCW5za5OlQVqs1EI .marker{fill:#333333;stroke:#333333;}#mermaid-svg-HCW5za5OlQVqs1EI .marker.cross{stroke:#333333;}#mermaid-svg-HCW5za5OlQVqs1EI svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-HCW5za5OlQVqs1EI p{margin:0;}#mermaid-svg-HCW5za5OlQVqs1EI .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-HCW5za5OlQVqs1EI .cluster-label text{fill:#333;}#mermaid-svg-HCW5za5OlQVqs1EI .cluster-label span{color:#333;}#mermaid-svg-HCW5za5OlQVqs1EI .cluster-label span p{background-color:transparent;}#mermaid-svg-HCW5za5OlQVqs1EI .label text,#mermaid-svg-HCW5za5OlQVqs1EI span{fill:#333;color:#333;}#mermaid-svg-HCW5za5OlQVqs1EI .node rect,#mermaid-svg-HCW5za5OlQVqs1EI .node circle,#mermaid-svg-HCW5za5OlQVqs1EI .node ellipse,#mermaid-svg-HCW5za5OlQVqs1EI .node polygon,#mermaid-svg-HCW5za5OlQVqs1EI .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-HCW5za5OlQVqs1EI .rough-node .label text,#mermaid-svg-HCW5za5OlQVqs1EI .node .label text,#mermaid-svg-HCW5za5OlQVqs1EI .image-shape .label,#mermaid-svg-HCW5za5OlQVqs1EI .icon-shape .label{text-anchor:middle;}#mermaid-svg-HCW5za5OlQVqs1EI .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-HCW5za5OlQVqs1EI .rough-node .label,#mermaid-svg-HCW5za5OlQVqs1EI .node .label,#mermaid-svg-HCW5za5OlQVqs1EI .image-shape .label,#mermaid-svg-HCW5za5OlQVqs1EI .icon-shape .label{text-align:center;}#mermaid-svg-HCW5za5OlQVqs1EI .node.clickable{cursor:pointer;}#mermaid-svg-HCW5za5OlQVqs1EI .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-HCW5za5OlQVqs1EI .arrowheadPath{fill:#333333;}#mermaid-svg-HCW5za5OlQVqs1EI .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-HCW5za5OlQVqs1EI .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-HCW5za5OlQVqs1EI .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HCW5za5OlQVqs1EI .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-HCW5za5OlQVqs1EI .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HCW5za5OlQVqs1EI .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-HCW5za5OlQVqs1EI .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-HCW5za5OlQVqs1EI .cluster text{fill:#333;}#mermaid-svg-HCW5za5OlQVqs1EI .cluster span{color:#333;}#mermaid-svg-HCW5za5OlQVqs1EI div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-HCW5za5OlQVqs1EI .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-HCW5za5OlQVqs1EI rect.text{fill:none;stroke-width:0;}#mermaid-svg-HCW5za5OlQVqs1EI .icon-shape,#mermaid-svg-HCW5za5OlQVqs1EI .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-HCW5za5OlQVqs1EI .icon-shape p,#mermaid-svg-HCW5za5OlQVqs1EI .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-HCW5za5OlQVqs1EI .icon-shape .label rect,#mermaid-svg-HCW5za5OlQVqs1EI .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-HCW5za5OlQVqs1EI .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-HCW5za5OlQVqs1EI .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-HCW5za5OlQVqs1EI :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Java 集合框架
Map(键值对)
HashMap
LinkedHashMap
TreeMap
Hashtable
Collection(单元素)
List(有序可重复)
ArrayList
LinkedList
Vector
Set(无序不可重复)
HashSet
LinkedHashSet
TreeSet
Queue(队列 FIFO)
PriorityQueue
ArrayDeque
LinkedList

读图指引Collection 体系存储单个元素,Map 体系存储键值对;List 关注顺序与索引,Set 关注去重,Queue/Deque 关注进出顺序,Map 关注键值映射。

下面是并发集合的架构图:
#mermaid-svg-AV1lHlExtOsmdbY9{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-AV1lHlExtOsmdbY9 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-AV1lHlExtOsmdbY9 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-AV1lHlExtOsmdbY9 .error-icon{fill:#552222;}#mermaid-svg-AV1lHlExtOsmdbY9 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-AV1lHlExtOsmdbY9 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-AV1lHlExtOsmdbY9 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-AV1lHlExtOsmdbY9 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-AV1lHlExtOsmdbY9 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-AV1lHlExtOsmdbY9 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-AV1lHlExtOsmdbY9 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-AV1lHlExtOsmdbY9 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-AV1lHlExtOsmdbY9 .marker.cross{stroke:#333333;}#mermaid-svg-AV1lHlExtOsmdbY9 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-AV1lHlExtOsmdbY9 p{margin:0;}#mermaid-svg-AV1lHlExtOsmdbY9 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-AV1lHlExtOsmdbY9 .cluster-label text{fill:#333;}#mermaid-svg-AV1lHlExtOsmdbY9 .cluster-label span{color:#333;}#mermaid-svg-AV1lHlExtOsmdbY9 .cluster-label span p{background-color:transparent;}#mermaid-svg-AV1lHlExtOsmdbY9 .label text,#mermaid-svg-AV1lHlExtOsmdbY9 span{fill:#333;color:#333;}#mermaid-svg-AV1lHlExtOsmdbY9 .node rect,#mermaid-svg-AV1lHlExtOsmdbY9 .node circle,#mermaid-svg-AV1lHlExtOsmdbY9 .node ellipse,#mermaid-svg-AV1lHlExtOsmdbY9 .node polygon,#mermaid-svg-AV1lHlExtOsmdbY9 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-AV1lHlExtOsmdbY9 .rough-node .label text,#mermaid-svg-AV1lHlExtOsmdbY9 .node .label text,#mermaid-svg-AV1lHlExtOsmdbY9 .image-shape .label,#mermaid-svg-AV1lHlExtOsmdbY9 .icon-shape .label{text-anchor:middle;}#mermaid-svg-AV1lHlExtOsmdbY9 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-AV1lHlExtOsmdbY9 .rough-node .label,#mermaid-svg-AV1lHlExtOsmdbY9 .node .label,#mermaid-svg-AV1lHlExtOsmdbY9 .image-shape .label,#mermaid-svg-AV1lHlExtOsmdbY9 .icon-shape .label{text-align:center;}#mermaid-svg-AV1lHlExtOsmdbY9 .node.clickable{cursor:pointer;}#mermaid-svg-AV1lHlExtOsmdbY9 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-AV1lHlExtOsmdbY9 .arrowheadPath{fill:#333333;}#mermaid-svg-AV1lHlExtOsmdbY9 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-AV1lHlExtOsmdbY9 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-AV1lHlExtOsmdbY9 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AV1lHlExtOsmdbY9 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-AV1lHlExtOsmdbY9 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AV1lHlExtOsmdbY9 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-AV1lHlExtOsmdbY9 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-AV1lHlExtOsmdbY9 .cluster text{fill:#333;}#mermaid-svg-AV1lHlExtOsmdbY9 .cluster span{color:#333;}#mermaid-svg-AV1lHlExtOsmdbY9 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-AV1lHlExtOsmdbY9 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-AV1lHlExtOsmdbY9 rect.text{fill:none;stroke-width:0;}#mermaid-svg-AV1lHlExtOsmdbY9 .icon-shape,#mermaid-svg-AV1lHlExtOsmdbY9 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-AV1lHlExtOsmdbY9 .icon-shape p,#mermaid-svg-AV1lHlExtOsmdbY9 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-AV1lHlExtOsmdbY9 .icon-shape .label rect,#mermaid-svg-AV1lHlExtOsmdbY9 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-AV1lHlExtOsmdbY9 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-AV1lHlExtOsmdbY9 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-AV1lHlExtOsmdbY9 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} java.util.concurrent 并发集合
ConcurrentHashMap
CopyOnWriteArrayList
CopyOnWriteArraySet
ConcurrentLinkedQueue
BlockingQueue
ArrayBlockingQueue
LinkedBlockingQueue

并发场景 :当多个线程同时访问集合时,应使用 java.util.concurrent 包下的线程安全集合,避免数据不一致和并发异常。

一、集合框架概览

Java 集合框架主要包含两大接口体系:

  • Collection :存储单个元素,派生出 ListSetQueue 等子接口。
  • Map :存储键值对,与 Collection 接口独立,但同属集合框架。

核心接口关系图(简化):

text 复制代码
Collection
├── List          (有序、可重复)
├── Set           (无序、不可重复)
└── Queue         (队列,FIFO)
    └── Deque     (双端队列)

Map               (键值对)
├── HashMap
├── LinkedHashMap
├── TreeMap
└── Hashtable

所有集合接口和实现类都位于 java.util 包中,并发集合位于 java.util.concurrent 包中。

二、核心接口

1. Collection 接口

Collection 是所有单元素集合的根接口,定义了基本操作:

java 复制代码
Collection<String> collection = new ArrayList<>();
collection.add("apple");
collection.remove("apple");
boolean contains = collection.contains("apple");
int size = collection.size();
boolean empty = collection.isEmpty();
collection.clear();

2. List 接口

List 是有序集合,允许重复元素,可以通过索引访问。

java 复制代码
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("Java");         // 允许重复
String first = list.get(0);       // "Java"
int index = list.indexOf("Python"); // 1
list.set(1, "Go");         // 替换
list.remove(0);            // 按索引删除

3. Set 接口

Set 不允许重复元素,通常用于去重。

java 复制代码
Set<String> set = new HashSet<>();
set.add("apple");
set.add("banana");
set.add("apple");   // 不会添加,已存在
boolean contains = set.contains("apple"); // true

4. Queue 接口

Queue 用于队列操作,支持 FIFO(先进先出)。

java 复制代码
Queue<String> queue = new LinkedList<>();
queue.offer("task1");   // 入队
queue.offer("task2");
String head = queue.poll();  // 出队,返回并移除队头,空时返回 null
String peek = queue.peek();  // 查看队头,不移除

5. Deque 接口

Deque 是双端队列,可作为栈或队列使用。

java 复制代码
Deque<String> deque = new ArrayDeque<>();
deque.addFirst("a");   // 头部添加
deque.addLast("b");    // 尾部添加
deque.removeFirst();   // 头部移除
deque.removeLast();    // 尾部移除

// 作为栈使用
Deque<Integer> stack = new ArrayDeque<>();
stack.push(1);         // 压栈
stack.push(2);
int top = stack.pop(); // 弹栈,2

6. Map 接口

Map 存储键值对,键唯一,值可重复。

java 复制代码
Map<String, Integer> map = new HashMap<>();
map.put("apple", 3);
map.put("banana", 5);
int count = map.get("apple");      // 3
boolean hasKey = map.containsKey("apple");
map.remove("apple");
map.putIfAbsent("banana", 10);     // 如果键不存在则放入
int size = map.size();

三、常用实现类详解

1. List 实现类

ArrayList

  • 基于动态数组实现,支持随机访问,查询快(O(1)),增删慢(需要移动元素)。
  • 非线程安全。
  • 默认初始容量 10,扩容为原容量的 1.5 倍。
java 复制代码
List<String> arrayList = new ArrayList<>();

LinkedList

  • 基于双向链表实现,查询慢(O(n)),增删快(O(1))。
  • 同时实现了 ListDeque 接口,可作为列表、队列、栈使用。
  • 非线程安全。
java 复制代码
LinkedList<String> linkedList = new LinkedList<>();
linkedList.addFirst("first");
linkedList.addLast("last");

Vector / Stack

  • Vector 是线程安全的 ArrayList(方法加锁),性能较差,已不推荐使用。
  • Stack 继承自 Vector,是线程安全的栈,推荐使用 ArrayDeque 替代。

2. Set 实现类

HashSet

  • 基于 HashMap 实现,无序,不允许重复。
  • 查询和插入复杂度 O(1)。
  • 元素需要正确实现 hashCode()equals()
java 复制代码
Set<String> hashSet = new HashSet<>();

LinkedHashSet

  • 继承自 HashSet,内部使用链表维护插入顺序。
  • 迭代顺序与插入顺序一致。
java 复制代码
Set<String> linkedHashSet = new LinkedHashSet<>();

TreeSet

  • 基于红黑树实现,元素自动排序(自然顺序或自定义比较器)。
  • 查询、插入复杂度 O(log n)。
  • 元素必须实现 Comparable 或传入 Comparator
java 复制代码
Set<Integer> treeSet = new TreeSet<>();
treeSet.add(5);
treeSet.add(2);
treeSet.add(8);
// 迭代顺序:2, 5, 8

3. Queue 实现类

PriorityQueue

  • 基于优先堆实现,元素按优先级出队,不保证 FIFO。
  • 默认最小堆(自然顺序),可传入比较器自定义优先级。
java 复制代码
Queue<Integer> pq = new PriorityQueue<>();
pq.offer(3);
pq.offer(1);
pq.offer(2);
while (!pq.isEmpty()) {
    System.out.println(pq.poll()); // 1, 2, 3
}

ArrayDeque

  • 基于循环数组实现的双端队列,可作为栈或队列使用。
  • LinkedList 性能更好,推荐使用。
  • 不允许 null 元素。
java 复制代码
Deque<Integer> deque = new ArrayDeque<>();

4. Map 实现类

HashMap

  • 基于哈希表实现,无序,键唯一。
  • 查询和插入复杂度 O(1)。
  • 键可以为 null(最多一个),值可以为 null
  • JDK 8 以后,当链表长度超过 8 且数组长度超过 64 时,链表转为红黑树,避免退化。
java 复制代码
Map<String, Integer> hashMap = new HashMap<>();

LinkedHashMap

  • 继承自 HashMap,维护双向链表保持插入顺序(或访问顺序)。
  • 可用于实现 LRU 缓存。
java 复制代码
Map<String, Integer> linkedHashMap = new LinkedHashMap<>();

TreeMap

  • 基于红黑树实现,键自动排序。
  • 查询、插入复杂度 O(log n)。
  • 键必须实现 Comparable 或传入 Comparator
java 复制代码
Map<String, Integer> treeMap = new TreeMap<>();

Hashtable

  • 线程安全的 HashMap(方法加锁),性能差,已不推荐使用。
  • 键和值都不允许为 null
  • 推荐使用 ConcurrentHashMap 替代。

四、遍历集合

1. 增强 for 循环

java 复制代码
List<String> list = List.of("a", "b", "c");
for (String s : list) {
    System.out.println(s);
}

2. Iterator 迭代器

java 复制代码
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String s = iterator.next();
    if (s.equals("b")) {
        iterator.remove(); // 安全删除
    }
}

注意 :使用 for-each 时不能直接修改集合结构,否则会抛出 ConcurrentModificationException。应使用迭代器的 remove() 方法,或使用并发集合。

3. ListIterator(仅 List)

支持双向遍历和修改元素:

java 复制代码
ListIterator<String> listIterator = list.listIterator();
while (listIterator.hasNext()) {
    String s = listIterator.next();
    if (s.equals("a")) {
        listIterator.set("A"); // 替换
    }
}

4. Stream API

JDK 8 引入的流式操作,适合过滤、映射、聚合等:

java 复制代码
List<String> filtered = list.stream()
        .filter(s -> s.length() > 1)
        .map(String::toUpperCase)
        .toList(); // JDK 16+

五、不可变集合与工厂方法

1. List.of() / Set.of() / Map.of()

JDK 9 引入的不可变集合工厂方法:

java 复制代码
List<String> immutableList = List.of("a", "b", "c");
Set<Integer> immutableSet = Set.of(1, 2, 3);
Map<String, Integer> immutableMap = Map.of("apple", 3, "banana", 5);

这些集合是不可变的,不能添加、删除或修改元素,线程安全。

2. Collections.unmodifiableXXX()

将可变集合包装为不可变视图:

java 复制代码
List<String> mutableList = new ArrayList<>();
List<String> unmodifiableList = Collections.unmodifiableList(mutableList);

六、线程安全集合

1. 同步包装器

java 复制代码
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
Map<String, Integer> syncMap = Collections.synchronizedMap(new HashMap<>());

注意:使用同步包装器时,遍历需要手动加锁,否则可能抛出异常。

2. 并发集合(推荐)

java.util.concurrent 包提供了高性能的并发集合:

  • ConcurrentHashMap :线程安全的 HashMap,采用分段锁/CAS,性能优于 Hashtable
  • CopyOnWriteArrayList:写时复制,适合读多写少的场景。
  • CopyOnWriteArraySet :基于 CopyOnWriteArrayList 实现。
  • ConcurrentLinkedQueue:无界非阻塞队列。
  • BlockingQueue 接口及实现(ArrayBlockingQueueLinkedBlockingQueue 等):支持阻塞操作,适合生产者-消费者模式。
java 复制代码
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
CopyOnWriteArrayList<String> cowList = new CopyOnWriteArrayList<>();

七、集合工具类

1. Collections

提供排序、查找、反转、填充等静态方法:

java 复制代码
List<Integer> list = new ArrayList<>(List.of(5, 2, 8, 1));
Collections.sort(list);                // 排序
Collections.reverse(list);             // 反转
Collections.shuffle(list);             // 打乱
int max = Collections.max(list);       // 最大值
int freq = Collections.frequency(list, 2); // 元素出现次数

2. Arrays

数组与集合的转换:

java 复制代码
String[] array = {"a", "b", "c"};
List<String> list = Arrays.asList(array); // 数组转 List(固定大小,不能增删)
List<String> mutableList = new ArrayList<>(Arrays.asList(array)); // 可变 List

String[] newArray = list.toArray(new String[0]); // List 转数组

八、JDK 21 新特性:有序集合(Sequenced Collections)

JDK 21 引入了 Sequenced Collections(JEP 431),为有序集合提供了统一的接口,解决了之前 ListSortedSetLinkedHashSet 等有序集合访问首尾元素方式不一致的问题。

新增接口:

  • SequencedCollection :继承自 Collection,新增 getFirst()getLast()removeFirst()removeLast()reversed() 等方法。
  • SequencedSet :继承自 SetSequencedCollection
  • SequencedMap :继承自 Map,新增 firstEntry()lastEntry()pollFirstEntry()pollLastEntry()reversed() 等方法。

实现类影响:

  • ListArrayListLinkedList)自动实现 SequencedCollection
  • LinkedHashSet 实现了 SequencedSet
  • SortedSetTreeSet)实现了 SequencedSet
  • LinkedHashMap 实现了 SequencedMap
  • SortedMapTreeMap)实现了 SequencedMap

使用示例:

java 复制代码
List<String> list = new ArrayList<>(List.of("a", "b", "c"));
String first = list.getFirst();      // "a"(之前需要 list.get(0))
String last = list.getLast();        // "c"(之前需要 list.get(list.size()-1))
List<String> reversed = list.reversed(); // 反向视图,不复制数据

LinkedHashSet<String> set = new LinkedHashSet<>(List.of("x", "y", "z"));
String firstSet = set.getFirst();    // "x"

LinkedHashMap<String, Integer> map = new LinkedHashMap<>();
map.put("one", 1);
map.put("two", 2);
Map.Entry<String, Integer> firstEntry = map.firstEntry(); // one=1

这些方法让有序集合的操作更加简洁和统一,尤其适合需要访问首尾元素的场景(如队列、缓存)。

九、集合选择建议

场景 推荐集合
需要随机访问、频繁查询 ArrayList
频繁在头部/中间插入删除 LinkedListArrayDeque
去重且不关心顺序 HashSet
去重且需要保持插入顺序 LinkedHashSet
去重且需要排序 TreeSet
键值对存储、快速查找 HashMap
键值对且需要插入顺序 LinkedHashMap
键值对且需要排序 TreeMap
需要队列 FIFO ArrayDequeLinkedList
需要优先级队列 PriorityQueue
需要栈 LIFO ArrayDeque(推荐)
多线程并发访问 ConcurrentHashMapCopyOnWriteArrayList
不可变集合 List.of()Set.of()Map.of()

十、最佳实践

  1. 优先使用接口类型声明集合 ,例如 List<String> list = new ArrayList<>();,方便替换实现。
  2. 指定初始容量:对于已知大小的集合,创建时指定容量可减少扩容开销。
  3. 避免在循环中使用 + 拼接字符串,同理,在循环中频繁增删元素时选择合适的数据结构。
  4. 正确实现 hashCode()equals() :使用 HashSetHashMap 时,自定义对象必须正确覆写这两个方法。
  5. 使用泛型:避免原始类型,确保类型安全。
  6. 遍历时修改集合要小心 :使用迭代器的 remove() 方法,或使用并发集合,或先收集待删除元素再统一删除。
  7. 优先使用不可变集合 :对于不需要修改的集合,使用 List.of() 等工厂方法,更安全且节省内存。
  8. 利用 JDK 21 的有序集合方法 :访问首尾元素时使用 getFirst()/getLast(),代码更清晰。

十一、热点面试题精讲

集合是 Java 面试的高频考点,下面梳理几类最常见的面试题,并给出答题要点。

1. ArrayList 与 LinkedList 的区别?

对比维度 ArrayList LinkedList
底层结构 动态数组 双向链表
随机访问 O(1),通过索引直接定位 O(n),需从头遍历
头部/中间插入删除 O(n),需移动元素 O(1),只需改指针(定位到节点后)
内存占用 连续内存,更紧凑 每个节点额外存储前后指针
适用场景 查询多、增删少 频繁在头部/中间增删

答题要点 :先讲底层结构差异,再引申到复杂度差异,最后落到「查询多选 ArrayList,增删多选 LinkedList」的结论。可补充:LinkedList 同时实现了 Deque,可作队列/栈使用。

2. HashMap 的底层实现原理?

答题要点(按版本演进回答):

  • JDK 7 及以前:数组 + 链表,采用头插法。
  • JDK 8 及以后:数组 + 链表 + 红黑树。当链表长度超过 8 且数组长度超过 64 时,链表转为红黑树,将最坏时间复杂度从 O(n) 优化为 O(log n)。
  • put 流程 :计算 key 的 hashCode() → 扰动函数二次散列 → (n - 1) & hash 定位桶下标 → 若为空直接放入,否则遍历链表/红黑树,key 相同则覆盖,否则插入。
  • 扩容机制 :默认初始容量 16,负载因子 0.75,当元素个数超过 容量 × 负载因子 时扩容为原来的 2 倍。
java 复制代码
// 扰动函数(JDK 8)
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

3. HashMap 与 Hashtable、ConcurrentHashMap 的区别?

对比维度 HashMap Hashtable ConcurrentHashMap
线程安全 是(全表加锁) 是(分段锁/CAS)
允许 null 键值
性能 最高
推荐度 单线程使用 不推荐 并发场景推荐

答题要点 :强调 Hashtablesynchronized 锁住整个表,并发度低;ConcurrentHashMap 在 JDK 8 后采用 CAS + synchronized 锁桶,并发度大幅提升。同时指出 ConcurrentHashMap 不允许 null 键值,是为了避免并发下的二义性。

4. 为什么 HashMap 的容量是 2 的幂次方?

答题要点

  • 计算桶下标时使用 (n - 1) & hash 代替取模运算,位运算更快。
  • n 为 2 的幂时,(n - 1) & hash 等价于 hash % n,且结果分布更均匀。
  • 扩容时元素要么留在原位置,要么移动到「原位置 + 旧容量」处,重排高效。

5. HashSet 如何保证元素不重复?

答题要点HashSet 底层基于 HashMap 实现,元素作为 HashMap 的 key 存储,value 统一为一个固定对象。判断重复依赖 hashCode()equals():先比较哈希值,哈希相同再调用 equals() 确认。因此自定义对象放入 HashSet 时必须正确覆写这两个方法。

6. 遍历集合时如何安全地删除元素?

答题要点 :for-each 遍历时直接删除会抛出 ConcurrentModificationException。推荐三种方式:

java 复制代码
// 方式一:使用 Iterator 的 remove()
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    if (it.next().equals("b")) {
        it.remove();
    }
}

// 方式二:使用 removeIf()(JDK 8+,最简洁)
list.removeIf(s -> s.equals("b"));

// 方式三:先收集再统一删除
List<String> toRemove = list.stream()
        .filter(s -> s.equals("b"))
        .toList();
list.removeAll(toRemove);

7. 如何实现一个 LRU 缓存?

答题要点LinkedHashMap 支持访问顺序(accessOrder=true),重写 removeEldestEntry() 即可实现 LRU:

java 复制代码
class LRUCache<K, V> extends LinkedHashMap<K, V> {
    private final int capacity;

    public LRUCache(int capacity) {
        super(capacity, 0.75f, true); // accessOrder=true,按访问顺序
        this.capacity = capacity;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        return size() > capacity; // 超过容量时移除最久未访问的条目
    }
}

8. 什么是快速失败(fail-fast)与安全失败(fail-safe)?

答题要点

  • fail-fast(快速失败)ArrayListHashMap 等普通集合在遍历时若结构被修改,立即抛出 ConcurrentModificationException。原理是迭代器维护 modCount 计数器,遍历时校验是否被修改。
  • fail-safe(安全失败)CopyOnWriteArrayListConcurrentHashMap 等并发集合在遍历时基于快照,不会抛出异常,但遍历结果可能不是最新的。

总结

Java 集合框架提供了丰富的数据结构和算法支持,掌握核心接口与实现类的特性,能够帮助我们在不同场景下做出合适的选择。JDK 21 引入的有序集合接口进一步提升了 API 的一致性,让代码更加简洁。在实际开发中,应结合性能、线程安全和功能需求,选择最合适的集合类,并遵循最佳实践,编写健壮、高效的代码。

相关推荐
宋军涛1 小时前
Windows 操作系统【任务计划程序】简单使用
服务器·windows
蜡台1 小时前
Kotlin 五大作用域函数详解|let/run/apply/also/with 选型指南+实战避坑
android·java·kotlin
AC赳赳老秦2 小时前
农产品公开数据应用:OpenClaw 抓取农产品价格、产销公开数据,实现农产品行情动态监测
java·c语言·javascript·python·php·deepseek·openclaw
1001101_QIA2 小时前
从 CPU 到 GPU:高速缓存、指令并行与 CUDA 执行原理入门
java·后端·spring
API快乐传递者2 小时前
淘宝海外商品详情接口实战指南:从全球开放平台到跨境铺货的全链路方案
java·前端·数据库
邪修king2 小时前
Re: Linux系统篇(十八):进程篇(七): 进程深度解析:从 fork 创建到退出的完整旅程(附写时拷贝原理 + 代码实战)
java·linux·运维
m0_587383002 小时前
24小时自助健身系统源码实战:从架构设计到部署落地
java·架构·系统架构·需求分析
卓怡学长2 小时前
w156一周穿搭App的设计与实现
java·spring boot·spring·maven·intellij-idea