2992 字
15 分钟

Java基本数据结构与高频接口实战手册

1. Java 基本数据结构怎么选#

1.1 Array(数组)#

  • 访问:按下标 O(1)
  • 插入删除:中间位置通常 O(n)
  • 适用:固定长度、频繁随机访问。
int[] arr = {10, 20, 30};
System.out.println(arr[1]); // 20

1.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); // []
}
}

常见易错点:

  1. remove(int index)remove(Object o) 是重载,List<Integer> 时要特别注意。
  2. 边遍历边删除不要直接在 for-eachremove,优先用 removeIf 或迭代器。
  3. 如果经常在头部插入删除,ArrayList 不如 LinkedList 合适。

1.3 LinkedList#

  • 链表结构,首尾插入删除友好。
  • 按索引访问慢。
  • 也实现了 Deque,可当队列/栈用。
LinkedList<String> linked = new LinkedList<>();
linked.addFirst("first");
linked.addLast("last");
System.out.println(linked.removeFirst()); // first

1.4 HashMap / HashSet#

  • HashMap:键值映射,平均查找 O(1)
  • HashSet:基于哈希的去重集合。
  • 两者都支持 removeclear 等删除方法。
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
}
}

删除方法速记:

  1. Map.remove(key):按 key 删除并返回旧值。
  2. Map.remove(key, value):key 和 value 同时匹配才删除,返回布尔值。
  3. Set.remove(element):删除指定元素,返回布尔值。
  4. Set.removeIf(predicate):按条件批量删除。
  5. 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]
}
}

使用建议:

  1. Arrays.equals 比较的是值,不是引用地址。
  2. binarySearch 前必须先确保有序,否则结果不可靠。
  3. 日志打印数组尽量用 Arrays.toString,不要直接打印引用。

1.8 全数据结构 CRUD 速查#

1.8.1 Array 的 CRUD#

  1. C(新增):固定长度,通常是新建更大数组并拷贝。
  2. R(查询):arr[index]
  3. U(修改):arr[index] = newValue
  4. 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#

  1. C:add(e)add(index, e)
  2. R:get(index)contains(e)indexOf(e)
  3. U:set(index, e)
  4. 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#

  1. C:add/addFirst/addLast
  2. R:get(index)getFirst/getLast
  3. U:set(index, e)
  4. 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#

  1. C:putputIfAbsent
  2. R:getgetOrDefaultcontainsKey
  3. U:put(覆盖)、replacecomputeIfPresent
  4. 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#

  1. C:add
  2. R:contains
  3. U:Set 没有“就地更新”,通常 remove(old) + add(new)
  4. D:removeremoveIfclear
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#

  1. C:put
  2. R:getfirstKeylastKeyceilingKey/floorKey
  3. U:replacecomputeIfPresent
  4. D:removepollFirstEntrypollLastEntryclear
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#

  1. C:add
  2. R:containsfirst/lastceiling/floor
  3. U:同 Set,一般删除旧值再新增新值。
  4. D:removepollFirst/pollLastclear
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)#

  1. C:offer
  2. R:peekelement(空队列会抛异常)。
  3. U:Queue 无随机更新,通常出队后再入队。
  4. D:pollremove(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(双端)#

  1. C:offerFirst/offerLast
  2. R:peekFirst/peekLast
  3. U:删除旧值再从头/尾插入新值。
  4. 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(优先级队列)#

  1. C:offer
  2. R:peek(看堆顶)、contains
  3. U:元素优先级变化后,通常 remove(old) + offer(new)
  4. D:pollremove(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 辅助操作:

  1. C:copyOf 扩容新增。
  2. R:binarySearch(有序数组)。
  3. U:fill 批量改值。
  4. D:常用 copyOfRange + System.arraycopy 配合实现删除。

2. Queue 接口速查(重点)#

最常用实现:ArrayDequeLinkedList

2.1 核心方法和行为#

  1. 入队:offer(e),成功返回 true
  2. 出队:poll(),队空返回 null
  3. 看队头:peek(),队空返回 null
  4. 判空:isEmpty()
  5. 大小:size()
  6. 异常版本: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 pollremove 的区别#

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 常用方法#

  1. 头部入队:offerFirst(e)
  2. 尾部入队:offerLast(e)
  3. 头部出队:pollFirst()
  4. 尾部出队:pollLast()
  5. 栈语义: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 核心特性#

  1. 默认是小顶堆(最小值先出)。
  2. 可传比较器变成大顶堆或自定义优先级。
  3. 常用方法:offerpeekpollisEmptysize

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 队列行为相关#

  1. PriorityQueue 遍历结果不是全局有序,只有 poll 出来的顺序有保障。
  2. Queue 空队列场景下尽量用 poll/peek,少用 remove/element

7.2 集合与并发相关#

  1. List.of/Set.of/Map.of 是不可变集合,不能增删。
  2. 并发环境别直接用 ArrayDeque/HashMap,要换并发容器。

8. 总结#

8.1 三条速记#

如果你只想记最关键的:

  1. FIFO 用 Queueoffer + poll + peek + isEmpty
  2. 有优先级用 PriorityQueue:比较器决定出队顺序。
  3. 统计和分组优先用 mergecomputeIfAbsentgroupingBy

支持与分享

如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!

赞助
Java基本数据结构与高频接口实战手册
https://blog.superjeason.qzz.io/posts/JavaDataStructuresAndHighFreqApis/
作者
SuperJeason
发布于
2026-02-13
许可协议
CC BY-NC-SA 4.0
Profile Image of the Author
SuperJeason
立于皓月之边,不弱星光之势
公告
欢迎来到我的博客!这是一则示例公告。
分类
标签
站点统计
文章
5
分类
3
标签
20
总字数
7,008
运行时长
0
最后活动
0 天前

目录