2992 字
15 分钟
Java基本数据结构与高频接口实战手册
1. Java 基本数据结构怎么选
1.1 Array(数组)
- 访问:按下标
O(1)。 - 插入删除:中间位置通常
O(n)。 - 适用:固定长度、频繁随机访问。
int[] arr = {10, 20, 30};System.out.println(arr[1]); // 201.2 ArrayList
- 本质是动态数组。
- 随机访问快,尾部追加快。
- 中间插入和删除相对慢。
import java.util.ArrayList;import java.util.List;
public class ArrayListCrudDemo { public static void main(String[] args) { List<String> list = new ArrayList<>();
// 1) 新增 list.add("A"); // 尾部追加 list.add("B"); list.add(1, "X"); // 指定索引插入,结果 [A, X, B]
// 2) 查询 System.out.println(list.get(0)); // A System.out.println(list.contains("B"));// true System.out.println(list.indexOf("X")); // 1 System.out.println(list.size()); // 3
// 3) 修改 list.set(2, "C"); // [A, X, C]
// 4) 删除 String removedByIndex = list.remove(1); // 删除索引 1 的元素 X boolean removedByValue = list.remove("A"); // 删除元素 A System.out.println(removedByIndex); // X System.out.println(removedByValue); // true
// 5) 遍历 for (String item : list) { System.out.println(item); }
// 6) 条件删除 list.removeIf(s -> s.startsWith("C")); System.out.println(list); // [] }}常见易错点:
remove(int index)和remove(Object o)是重载,List<Integer>时要特别注意。- 边遍历边删除不要直接在
for-each里remove,优先用removeIf或迭代器。 - 如果经常在头部插入删除,
ArrayList不如LinkedList合适。
1.3 LinkedList
- 链表结构,首尾插入删除友好。
- 按索引访问慢。
- 也实现了
Deque,可当队列/栈用。
LinkedList<String> linked = new LinkedList<>();linked.addFirst("first");linked.addLast("last");System.out.println(linked.removeFirst()); // first1.4 HashMap / HashSet
HashMap:键值映射,平均查找O(1)。HashSet:基于哈希的去重集合。- 两者都支持
remove、clear等删除方法。
import java.util.HashMap;import java.util.HashSet;import java.util.Map;import java.util.Set;
public class MapSetCrudDemo { public static void main(String[] args) { // ---------- Map: 增删改查 ---------- Map<String, Integer> age = new HashMap<>();
// 1) 新增 age.put("Alice", 18); age.put("Bob", 20); age.putIfAbsent("Alice", 99); // 已存在则不覆盖
// 2) 查询 System.out.println(age.get("Alice")); // 18 System.out.println(age.getOrDefault("Tom", -1)); // -1 System.out.println(age.containsKey("Bob")); // true System.out.println(age.containsValue(20)); // true
// 3) 修改 age.put("Bob", 21); // 覆盖旧值 age.replace("Alice", 19); // 仅当 key 存在时替换
// 4) 删除 Integer removed = age.remove("Bob"); // 按 key 删除,返回旧值 21 boolean removedPair = age.remove("Alice", 19); // key/value 同时匹配才删除 System.out.println(removed); // 21 System.out.println(removedPair); // true
// 5) 清空 age.clear(); System.out.println(age.isEmpty()); // true
// ---------- Set: 去重 + 删除 ---------- Set<String> set = new HashSet<>(); set.add("java"); set.add("java"); // 重复元素不会新增 set.add("go"); set.add("python");
// 查询 System.out.println(set.contains("go")); // true
// 删除 boolean removedGo = set.remove("go"); // 按元素删除 set.removeIf(s -> s.startsWith("py")); // 条件删除 System.out.println(removedGo); // true System.out.println(set); // [java](HashSet 顺序不保证)
// 清空 set.clear(); System.out.println(set.isEmpty()); // true }}删除方法速记:
Map.remove(key):按 key 删除并返回旧值。Map.remove(key, value):key 和 value 同时匹配才删除,返回布尔值。Set.remove(element):删除指定元素,返回布尔值。Set.removeIf(predicate):按条件批量删除。Map.clear()/Set.clear():清空集合。
1.5 TreeMap / TreeSet
- 自动有序(红黑树)。
- 适合范围查询、有序输出。
TreeSet<Integer> tree = new TreeSet<>(List.of(5, 1, 3));System.out.println(tree); // [1, 3, 5]1.6 Queue / Deque / PriorityQueue
Queue:FIFO(先进先出)。Deque:双端队列,可做队列也可做栈。PriorityQueue:优先级队列(堆),不保证整体有序,只保证堆顶优先。
1.7 Arrays 工具类(重点补充)
Arrays 是数组处理最常用的工具类,核心能力包括排序、比较、查找、填充和拷贝。
import java.util.Arrays;
public class ArraysApiDemo { public static void main(String[] args) { int[] a = {5, 2, 9, 1}; int[] b = {1, 2, 5, 9};
// 1) 排序 Arrays.sort(a); // [1, 2, 5, 9] System.out.println(Arrays.toString(a));
// 2) 比较(元素和顺序都相同才为 true) System.out.println(Arrays.equals(a, b)); // true
// 3) 二分查找(前提:数组已排序) int idx = Arrays.binarySearch(a, 5); System.out.println(idx); // 2
// 4) 填充 int[] filled = new int[4]; Arrays.fill(filled, 7); // [7, 7, 7, 7] System.out.println(Arrays.toString(filled));
// 5) 拷贝扩容 int[] copied = Arrays.copyOf(a, 6); // 长度扩成 6,不足补 0 System.out.println(Arrays.toString(copied)); // [1, 2, 5, 9, 0, 0]
// 6) 区间排序 [from, to) int[] part = {9, 4, 7, 1, 8}; Arrays.sort(part, 1, 4); // 仅排序索引 1~3 System.out.println(Arrays.toString(part)); // [9, 1, 4, 7, 8] }}使用建议:
Arrays.equals比较的是值,不是引用地址。- 用
binarySearch前必须先确保有序,否则结果不可靠。 - 日志打印数组尽量用
Arrays.toString,不要直接打印引用。
1.8 全数据结构 CRUD 速查
1.8.1 Array 的 CRUD
- C(新增):固定长度,通常是新建更大数组并拷贝。
- R(查询):
arr[index]。 - U(修改):
arr[index] = newValue。 - D(删除):数组没有“真删除”,需要新建数组并跳过指定元素。
import java.util.Arrays;
public class ArrayCrudDemo { public static void main(String[] args) { int[] arr = {10, 20, 30};
// C: 新增元素 40(扩容 + 拷贝) arr = Arrays.copyOf(arr, arr.length + 1); arr[arr.length - 1] = 40;
// R: 查询 System.out.println(arr[1]); // 20
// U: 修改 arr[0] = 99;
// D: 删除索引 1 的元素 arr = removeAt(arr, 1); System.out.println(Arrays.toString(arr)); // [99, 30, 40] }
static int[] removeAt(int[] arr, int idx) { int[] res = new int[arr.length - 1]; System.arraycopy(arr, 0, res, 0, idx); System.arraycopy(arr, idx + 1, res, idx, arr.length - idx - 1); return res; }}1.8.2 ArrayList 的 CRUD
- C:
add(e)、add(index, e)。 - R:
get(index)、contains(e)、indexOf(e)。 - U:
set(index, e)。 - D:
remove(index)、remove(obj)、removeIf(...)、clear()。
import java.util.ArrayList;import java.util.List;
public class ArrayListCrudSimpleDemo { public static void main(String[] args) { List<String> list = new ArrayList<>();
// C list.add("A"); list.add(1, "B");
// R System.out.println(list.get(0)); // A System.out.println(list.contains("B"));// true
// U list.set(1, "C");
// D list.remove("A"); list.removeIf(s -> s.startsWith("C")); System.out.println(list); // [] }}1.8.3 LinkedList 的 CRUD
- C:
add/addFirst/addLast。 - R:
get(index)、getFirst/getLast。 - U:
set(index, e)。 - D:
removeFirst/removeLast/remove(index)/remove(obj)/clear。
import java.util.LinkedList;
public class LinkedListCrudDemo { public static void main(String[] args) { LinkedList<String> linked = new LinkedList<>();
// C linked.addFirst("B"); linked.addLast("C"); linked.add(0, "A");
// R System.out.println(linked.getFirst()); // A System.out.println(linked.get(1)); // B
// U linked.set(2, "Z");
// D linked.removeFirst(); // 删除 A linked.remove("Z"); // 删除值 Z System.out.println(linked); // [B] }}1.8.4 HashMap 的 CRUD
- C:
put、putIfAbsent。 - R:
get、getOrDefault、containsKey。 - U:
put(覆盖)、replace、computeIfPresent。 - D:
remove(key)、remove(key, value)、clear()。
import java.util.HashMap;import java.util.Map;
public class HashMapCrudDemo { public static void main(String[] args) { Map<String, Integer> age = new HashMap<>();
// C age.put("Alice", 18); age.putIfAbsent("Bob", 20);
// R System.out.println(age.get("Alice")); // 18 System.out.println(age.containsKey("Bob")); // true
// U age.replace("Alice", 19); age.computeIfPresent("Bob", (k, v) -> v + 1); // 21
// D age.remove("Bob"); age.remove("Alice", 19); System.out.println(age.isEmpty()); // true }}1.8.5 HashSet 的 CRUD
- C:
add。 - R:
contains。 - U:Set 没有“就地更新”,通常
remove(old)+add(new)。 - D:
remove、removeIf、clear。
import java.util.HashSet;import java.util.Set;
public class HashSetCrudDemo { public static void main(String[] args) { Set<String> set = new HashSet<>();
// C set.add("java"); set.add("go");
// R System.out.println(set.contains("java")); // true
// U(模拟更新) set.remove("go"); set.add("golang");
// D set.remove("java"); set.removeIf(s -> s.startsWith("go")); System.out.println(set.isEmpty()); // true }}1.8.6 TreeMap 的 CRUD
- C:
put。 - R:
get、firstKey、lastKey、ceilingKey/floorKey。 - U:
replace、computeIfPresent。 - D:
remove、pollFirstEntry、pollLastEntry、clear。
import java.util.TreeMap;
public class TreeMapCrudDemo { public static void main(String[] args) { TreeMap<Integer, String> tm = new TreeMap<>();
// C tm.put(100, "A"); tm.put(200, "B"); tm.put(150, "C");
// R System.out.println(tm.get(150)); // C System.out.println(tm.firstKey()); // 100 System.out.println(tm.ceilingKey(160)); // 200
// U tm.replace(150, "C2");
// D tm.remove(100); tm.pollLastEntry(); // 删除最大 key System.out.println(tm); // {150=C2} }}1.8.7 TreeSet 的 CRUD
- C:
add。 - R:
contains、first/last、ceiling/floor。 - U:同 Set,一般删除旧值再新增新值。
- D:
remove、pollFirst/pollLast、clear。
import java.util.TreeSet;
public class TreeSetCrudDemo { public static void main(String[] args) { TreeSet<Integer> ts = new TreeSet<>();
// C ts.add(3); ts.add(1); ts.add(2);
// R System.out.println(ts.first()); // 1 System.out.println(ts.ceiling(2)); // 2
// U(模拟更新 2 -> 20) ts.remove(2); ts.add(20);
// D ts.pollFirst(); // 删除最小 ts.remove(20); System.out.println(ts); // [3] }}1.8.8 Queue 的 CRUD(FIFO)
- C:
offer。 - R:
peek、element(空队列会抛异常)。 - U:Queue 无随机更新,通常出队后再入队。
- D:
poll、remove(obj)、clear。
import java.util.ArrayDeque;import java.util.Queue;
public class QueueCrudDemo { public static void main(String[] args) { Queue<String> q = new ArrayDeque<>();
// C q.offer("A"); q.offer("B");
// R System.out.println(q.peek()); // A
// U(把队头 A 更新为 A1) String head = q.poll(); q.offer(head + "1");
// D q.remove("B"); q.poll(); // 删除队头 A1 System.out.println(q.isEmpty()); // true }}1.8.9 Deque 的 CRUD(双端)
- C:
offerFirst/offerLast。 - R:
peekFirst/peekLast。 - U:删除旧值再从头/尾插入新值。
- D:
pollFirst/pollLast/remove/clear。
import java.util.ArrayDeque;import java.util.Deque;
public class DequeCrudDemo { public static void main(String[] args) { Deque<String> dq = new ArrayDeque<>();
// C dq.offerFirst("B"); dq.offerFirst("A"); dq.offerLast("C");
// R System.out.println(dq.peekFirst()); // A System.out.println(dq.peekLast()); // C
// U(更新尾部 C -> Z) dq.pollLast(); dq.offerLast("Z");
// D dq.pollFirst(); dq.remove("B"); System.out.println(dq); // [Z] }}1.8.10 PriorityQueue 的 CRUD(优先级队列)
- C:
offer。 - R:
peek(看堆顶)、contains。 - U:元素优先级变化后,通常
remove(old)+offer(new)。 - D:
poll、remove(obj)、clear。
import java.util.Comparator;import java.util.PriorityQueue;
record Task(String name, int priority) {}
public class PriorityQueueCrudDemo { public static void main(String[] args) { PriorityQueue<Task> pq = new PriorityQueue<>(Comparator.comparingInt(Task::priority));
// C pq.offer(new Task("backup", 3)); pq.offer(new Task("hotfix", 1));
// R System.out.println(pq.peek()); // hotfix
// U(backup 优先级从 3 改为 0) pq.removeIf(t -> t.name().equals("backup")); pq.offer(new Task("backup", 0));
// D pq.poll(); // 删除最高优先级元素 pq.removeIf(t -> t.name().equals("hotfix")); System.out.println(pq.isEmpty()); // true }}1.8.11 Arrays 在 CRUD 中的辅助角色
Arrays 不是容器本身,但它常用于数组型数据的 C/R/U/D 辅助操作:
- C:
copyOf扩容新增。 - R:
binarySearch(有序数组)。 - U:
fill批量改值。 - D:常用
copyOfRange + System.arraycopy配合实现删除。
2. Queue 接口速查(重点)
最常用实现:ArrayDeque、LinkedList。
2.1 核心方法和行为
- 入队:
offer(e),成功返回true。 - 出队:
poll(),队空返回null。 - 看队头:
peek(),队空返回null。 - 判空:
isEmpty()。 - 大小:
size()。 - 异常版本:
add/remove/element,队空或失败时会抛异常。
2.2 完整示例(isEmpty + offer + poll + peek)
import java.util.ArrayDeque;import java.util.Queue;
public class QueueApiDemo { public static void main(String[] args) { Queue<String> queue = new ArrayDeque<>();
System.out.println(queue.isEmpty()); // true System.out.println(queue.size()); // 0
queue.offer("task-1"); queue.offer("task-2"); queue.offer("task-3");
System.out.println(queue.peek()); // task-1(只看不取) System.out.println(queue.size()); // 3
while (!queue.isEmpty()) { String task = queue.poll(); // 取并删除队头 System.out.println("processing: " + task); }
System.out.println(queue.poll()); // null(空队列安全返回) System.out.println(queue.isEmpty()); // true }}2.3 poll 和 remove 的区别
import java.util.ArrayDeque;import java.util.Queue;
public class QueueRemoveVsPoll { public static void main(String[] args) { Queue<Integer> q = new ArrayDeque<>();
System.out.println(q.poll()); // null
try { System.out.println(q.remove()); // 抛 NoSuchElementException } catch (Exception e) { System.out.println(e.getClass().getSimpleName()); } }}结论:业务里更推荐 poll(),避免空队列异常中断。
3. Deque 双端队列接口(实用)
Deque 同时支持头尾操作,接口非常丰富。
3.1 常用方法
- 头部入队:
offerFirst(e) - 尾部入队:
offerLast(e) - 头部出队:
pollFirst() - 尾部出队:
pollLast() - 栈语义:
push(e)/pop()
3.2 示例:双端任务池
import java.util.ArrayDeque;import java.util.Deque;
public class DequeDemo { public static void main(String[] args) { Deque<String> deque = new ArrayDeque<>();
deque.offerLast("normal-1"); deque.offerLast("normal-2"); deque.offerFirst("urgent-0");
System.out.println(deque.pollFirst()); // urgent-0 System.out.println(deque.pollLast()); // normal-2
deque.push("stack-A"); deque.push("stack-B"); System.out.println(deque.pop()); // stack-B }}4. PriorityQueue 接口速查(重点)
PriorityQueue 是堆结构,不是普通 FIFO 队列。
4.1 核心特性
- 默认是小顶堆(最小值先出)。
- 可传比较器变成大顶堆或自定义优先级。
- 常用方法:
offer、peek、poll、isEmpty、size。
4.2 示例一:默认最小堆
import java.util.PriorityQueue;
public class PriorityQueueMinHeapDemo { public static void main(String[] args) { PriorityQueue<Integer> pq = new PriorityQueue<>(); pq.offer(5); pq.offer(1); pq.offer(3);
while (!pq.isEmpty()) { System.out.println(pq.poll()); // 1, 3, 5 } }}4.3 示例二:最大堆(自定义比较器)
import java.util.Comparator;import java.util.PriorityQueue;
public class PriorityQueueMaxHeapDemo { public static void main(String[] args) { PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Comparator.reverseOrder()); maxHeap.offer(5); maxHeap.offer(1); maxHeap.offer(3);
System.out.println(maxHeap.peek()); // 5 System.out.println(maxHeap.poll()); // 5 System.out.println(maxHeap.poll()); // 3 System.out.println(maxHeap.poll()); // 1 }}4.4 示例三:按任务优先级调度
import java.util.PriorityQueue;
class Task { String name; int priority; // 数值越小优先级越高
Task(String name, int priority) { this.name = name; this.priority = priority; }}
public class PriorityTaskDemo { public static void main(String[] args) { PriorityQueue<Task> pq = new PriorityQueue<>((a, b) -> a.priority - b.priority);
pq.offer(new Task("backup", 3)); pq.offer(new Task("hotfix", 1)); pq.offer(new Task("report", 2));
while (!pq.isEmpty()) { Task t = pq.poll(); System.out.println(t.name + " -> p" + t.priority); } }}输出顺序是:hotfix -> report -> backup。
5. 高频“快捷接口”补充(Map / List / Set / Arrays)
5.1 Map 常用快捷接口
import java.util.*;
public class MapQuickApiDemo { public static void main(String[] args) { Map<String, Integer> freq = new HashMap<>();
freq.merge("java", 1, Integer::sum); freq.merge("java", 1, Integer::sum); freq.merge("go", 1, Integer::sum); System.out.println(freq.getOrDefault("java", 0)); // 2
freq.remove("go"); // 按 key 删除 freq.remove("java", 99); // key/value 不匹配,删除失败 freq.remove("java", 2); // key/value 匹配,删除成功
Map<String, List<String>> group = new HashMap<>(); group.computeIfAbsent("RD", k -> new ArrayList<>()).add("Alice"); group.computeIfAbsent("RD", k -> new ArrayList<>()).add("Bob");
System.out.println(group); // {RD=[Alice, Bob]} }}5.2 List 常用快捷接口
import java.util.*;
public class ListQuickApiDemo { public static void main(String[] args) { List<Integer> nums = new ArrayList<>(List.of(5, 1, 2, 8, 3, 2));
nums.add(0, 99); // 索引插入 nums.remove(1); // 按索引删除 nums.remove(Integer.valueOf(2)); // 按元素值删除(只删第一个匹配)
nums.removeIf(n -> n % 2 == 0); // 删除偶数 nums.replaceAll(n -> n * 10); // 每个元素乘 10 nums.sort(Integer::compareTo); // 升序排序
System.out.println(nums); }}5.3 Stream 一行管道示例
import java.util.List;import java.util.Map;import java.util.stream.Collectors;
public class StreamDemo { public static void main(String[] args) { List<String> words = List.of("java", "go", "java", "rust", "go", "java");
Map<String, Long> countMap = words.stream() .collect(Collectors.groupingBy(w -> w, Collectors.counting()));
System.out.println(countMap); // {java=3, go=2, rust=1} }}5.4 Arrays 常用快捷接口
import java.util.Arrays;
public class ArraysQuickApiDemo { public static void main(String[] args) { int[] arr = {4, 2, 8, 1};
Arrays.sort(arr); System.out.println(Arrays.toString(arr)); // [1, 2, 4, 8]
int[] another = {1, 2, 4, 8}; System.out.println(Arrays.equals(arr, another)); // true }}5.5 Set 常用快捷接口(含删除)
import java.util.HashSet;import java.util.Set;
public class SetQuickApiDemo { public static void main(String[] args) { Set<String> tags = new HashSet<>(); tags.add("java"); tags.add("go"); tags.add("python"); tags.add("java"); // 重复无效
tags.remove("go"); // 删除单个元素 tags.removeIf(t -> t.startsWith("py")); // 条件删除 tags.retainAll(Set.of("java", "rust")); // 只保留交集
System.out.println(tags); // [java](顺序不保证) }}6. 综合案例:普通队列 + 优先队列
6.1 场景说明
场景:系统里有普通任务和紧急任务。
处理策略:先处理紧急任务,再处理普通任务。
6.2 代码示例
import java.util.ArrayDeque;import java.util.Comparator;import java.util.PriorityQueue;import java.util.Queue;
class Job { String name; int priority; // 越小越紧急
Job(String name, int priority) { this.name = name; this.priority = priority; }}
public class SchedulerDemo { public static void main(String[] args) { Queue<Job> normalQueue = new ArrayDeque<>(); PriorityQueue<Job> urgentQueue = new PriorityQueue<>(Comparator.comparingInt(j -> j.priority));
normalQueue.offer(new Job("daily-report", 99)); normalQueue.offer(new Job("sync-data", 99)); urgentQueue.offer(new Job("hotfix-prod", 1)); urgentQueue.offer(new Job("security-patch", 2));
while (!urgentQueue.isEmpty() || !normalQueue.isEmpty()) { Job current = !urgentQueue.isEmpty() ? urgentQueue.poll() : normalQueue.poll(); System.out.println("run: " + current.name + ", p=" + current.priority); } }}6.3 适用场景
这个模式在“工单系统、消息处理、重试队列”里非常常见。
7. 常见坑
7.1 队列行为相关
PriorityQueue遍历结果不是全局有序,只有poll出来的顺序有保障。Queue空队列场景下尽量用poll/peek,少用remove/element。
7.2 集合与并发相关
List.of/Set.of/Map.of是不可变集合,不能增删。- 并发环境别直接用
ArrayDeque/HashMap,要换并发容器。
8. 总结
8.1 三条速记
如果你只想记最关键的:
- FIFO 用
Queue:offer + poll + peek + isEmpty。 - 有优先级用
PriorityQueue:比较器决定出队顺序。 - 统计和分组优先用
merge、computeIfAbsent、groupingBy。
支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!
Java基本数据结构与高频接口实战手册
https://blog.superjeason.qzz.io/posts/JavaDataStructuresAndHighFreqApis/