上一篇
java list怎么使用方法
- 后端开发
- 2025-08-11
- 44
Java List通过add()添加元素,get(index)获取,size()查长度,可用
Java中的List是java.util包下的核心接口之一,用于表示有序、可重复的元素集合,它继承了Collection接口的所有特性,并额外提供了基于索引的精确控制能力,以下是对其使用方法的系统性解析:
核心特征与常见实现类
| 特性 | 描述 |
|---|---|
| 有序性 | 元素按插入顺序存储,可通过索引快速访问 |
| 允许重复 | 同一元素可多次出现 |
| 允许null值 | 可以包含null元素 |
| 动态扩容 | 多数实现类支持自动扩容(如ArrayList) |
| 多种底层结构 | 不同实现类采用数组/链表/栈等不同数据结构 |
主流实现类对比表
| 实现类 | 底层结构 | 增删效率 | 随机访问效率 | 适用场景 | 线程安全 |
|---|---|---|---|---|---|
ArrayList |
动态数组 | 尾部快 头部慢 |
O(1) | 频繁随机访问/少量增删 | |
LinkedList |
双向链表 | 任意位置快 | O(n) | 频繁头尾操作/大数据量插入删除 | |
Vector |
动态数组 | 同ArrayList | O(1) | 古老线程安全版本(现推荐改用CopyOnWriteArrayList) |
|
CopyOnWriteArrayList |
写时复制数组 | 写入开销大 | O(1) | 高并发读多写少场景 |
核心方法详解(以ArrayList为例)
基础操作
import java.util.ArrayList;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
// 创建List实例
List<String> fruits = new ArrayList<>(); // 钻石操作符简化泛型声明
// 添加元素
fruits.add("Apple"); // 尾部追加 → [Apple]
fruits.add("Banana"); // → [Apple, Banana]
fruits.add(1, "Orange"); // 指定索引插入 → [Apple, Orange, Banana]
// 获取元素
System.out.println("第二个元素: " + fruits.get(1)); // 输出 Orange
// 修改元素
fruits.set(0, "Pear"); // 替换索引0元素 → [Pear, Orange, Banana]
// 删除元素
fruits.remove(1); // 删除索引1 → [Pear, Banana]
fruits.remove("Banana"); // 删除对象 → [Pear]
// 判断存在性
boolean hasApple = fruits.contains("Apple"); // false
}
}
批量操作
| 方法 | 功能 | 示例 |
|---|---|---|
addAll(Collection<? extends E> c) |
追加整个集合 | fruits.addAll(Arrays.asList("Grape", "Melon")) |
subList(int fromIndex, int toIndex) |
返回指定区间的子视图(原地修改影响源) | List<String> sub = fruits.subList(0, 2) |
clear() |
清空列表 | fruits.clear() |
特殊操作技巧
- 交换元素:需借助临时变量
String temp = fruits.get(i); fruits.set(i, fruits.get(j)); fruits.set(j, temp);
- 倒序遍历:结合
Collections.reverse()或手动逆序索引 - 固定大小限制:创建时指定初始容量避免频繁扩容
new ArrayList<>(initialCapacity); // 推荐设置为预期大小的120%
关键实现类的特性差异
ArrayList vs LinkedList性能测试
| 操作类型 | ArrayList耗时 |
LinkedList耗时 |
原因分析 |
|---|---|---|---|
| 尾部添加 | (最快) | 数组尾部直接赋值 | |
| 头部插入 | (最慢) | 数组需移动后续所有元素 | |
| 中间插入 | 链表只需修改前后指针 | ||
| 根据索引随机访问 | (最快) | (最慢) | 数组通过CPU缓存预取优化 |
| 遍历全部元素 | (最快) | 链表跳跃式访问无内存局部性 |
Vector的特殊性
- 历史遗留的线程安全类,所有公共方法均使用
synchronized修饰 - 已过时!现代开发推荐:
- 单线程环境:
ArrayList - 多线程环境:
CopyOnWriteArrayList(读多写少)或手动同步Collections.synchronizedList(new ArrayList<>())
- 单线程环境:
高级用法示例
排序与二分查找
List<Integer> numbers = new ArrayList<>(Arrays.asList(5, 3, 8, 1)); Collections.sort(numbers); // [1, 3, 5, 8] int index = Collections.binarySearch(numbers, 5); // 返回2(找到的位置)
自定义比较器排序
List<Student> students = ...; // Student类需实现Comparable或提供Comparator students.sort((a, b) -> a.getAge() b.getAge()); // 按年龄升序
不可变列表创建
List<String> immutableList = List.of("A", "B", "C"); // Java 9+
// 尝试修改会抛出UnsupportedOperationException
immutableList.add("D"); // Error!
注意事项与最佳实践
-
避免空指针异常:

- 始终检查
size()后再通过索引访问元素 - 使用
isEmpty()判断空列表而非size()==0
- 始终检查
-
迭代器安全:
- 结构化修改(遍历时删除/添加)会导致
ConcurrentModificationException - 解决方案:使用
Iterator的remove()方法或改用for循环倒序删除
- 结构化修改(遍历时删除/添加)会导致
-
内存优化:

ArrayList初始容量设为预计大小的120%可减少扩容次数- 高频插入/删除场景优先考虑
LinkedList
-
线程安全方案选择:
- 读多写少:
CopyOnWriteArrayList(内部使用写时复制机制) - 写多读少:
Collections.synchronizedList(new ArrayList<>())+合理锁粒度
- 读多写少:
相关问答FAQs
Q1: 什么时候应该选择ArrayList而不是LinkedList?
A: 当业务场景以随机访问为主时(如根据ID查询订单),ArrayList的O(1)时间复杂度优势明显;若主要进行频繁的插入/删除操作(如日志队列),则应选择LinkedList,实测数据显示,在百万级数据量下,ArrayList的随机访问速度比LinkedList快约3个数量级。
Q2: 为什么遍历ArrayList时修改会抛出ConcurrentModificationException?
A: 这是Java集合框架的快速失败机制(Fail-Fast)。ArrayList内部维护了一个modCount计数器,每次结构性修改(增删改)都会递增该值,迭代器的checkForComodification()方法会在每次next()操作前检查预期修改次数是否匹配实际修改次数,若检测到不一致(即遍历过程中发生了结构性修改),立即抛出异常,这种设计是为了及时发现并发修改问题,保证数据一致性,解决方案包括:①使用迭代器的remove()方法;②改用for循环倒序删除;③克隆新

