Java·关于List

List 是 Java 集合框架(java.util 包)中核心的有序、可重复 集合接口,继承自 Collection 接口,支持通过索引(下标)快速访问、修改元素,是日常开发中最常用的集合类型之一。

一、什么是 List?

1. 核心定义

List 是 Collection 接口的子接口,用于存储有序、可重复的元素集合,其核心特征是:

  • 有序性:元素的插入顺序与存储顺序一致,支持通过索引(0 起始)访问元素;
  • 可重复性:允许存储多个相同的元素(包括 null);
  • 索引操作:提供了基于索引的增删改查方法(这是 List 与 Set 最核心的区别)。

2. 与其他核心集合的区别

二、List 接口核心方法(含继承 + 独有)

List 继承了 Collection 接口的基础方法(如 add(E)remove(Object)size()isEmpty() 等),同时新增了基于索引的操作方法,核心方法如下:

1. 新增元素(基于索引)

java 复制代码
// 1. 在列表末尾添加元素(继承自Collection)
boolean add(E e);

// 2. 在指定索引index处插入元素,后续元素后移(List独有)
void add(int index, E element);

// 3. 将另一个集合的所有元素添加到当前列表末尾
boolean addAll(Collection<? extends E> c);

// 4. 将另一个集合的所有元素插入到指定索引处
boolean addAll(int index, Collection<? extends E> c);

2. 删除元素(基于索引 / 元素)

java 复制代码
// 1. 删除指定索引处的元素,返回被删除的元素(List独有)
E remove(int index);

// 2. 删除第一个匹配的元素(继承自Collection)
boolean remove(Object o);

// 3. 清空所有元素
void clear();

3. 修改元素(基于索引)

java 复制代码
// 替换指定索引处的元素,返回被替换的旧元素(List独有)
E set(int index, E element);

4. 查询元素(基于索引 / 元素)

java 复制代码
// 1. 获取指定索引处的元素(List独有)
E get(int index);

// 2. 返回第一个匹配元素的索引,无则返回-1(List独有)
int indexOf(Object o);

// 3. 返回最后一个匹配元素的索引,无则返回-1(List独有)
int lastIndexOf(Object o);

// 4. 判断集合是否包含指定元素(继承自Collection)
boolean contains(Object o);

5. 其他常用方法

java 复制代码
// 1. 返回List的子列表(左闭右开区间),注意:子列表是原列表的视图,修改会相互影响
List<E> subList(int fromIndex, int toIndex);

// 2. 将List转为数组
Object[] toArray();
<T> T[] toArray(T[] a);

// 3. 获取迭代器(支持遍历)
Iterator<E> iterator();

// 4. Java 8+ 新增:forEach遍历(函数式接口)
void forEach(Consumer<? super E> action);

三、List 的主要实现类(重点)

List 是接口,无法直接实例化,需使用其实现类。日常开发中最常用的实现类有 4 个,核心差异在于底层数据结构性能特性

关键补充:

  • ArrayList 扩容机制:初始容量为 10,负载因子 0.75,当元素个数达到 容量×负载因子 时,扩容为原容量的 1.5 倍(避免频繁扩容,可初始化时指定容量优化);
  • LinkedList 除了 List 方法,还实现了 Deque 接口,支持 addFirst()addLast()pollFirst()pop() 等队列 / 栈操作;
  • CopyOnWriteArrayList 适合读多写少(如配置缓存),写操作(add/remove)会复制原数组,开销较大,不适合频繁写的场景。

四、List 的使用(实战示例)

1. 实例化 List

推荐使用接口引用 + 实现类实例的方式(面向接口编程):

java 复制代码
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

public class ListDemo {
    public static void main(String[] args) {
        // 1. ArrayList(默认容量10)
        List<String> arrayList = new ArrayList<>();
        // 初始化指定容量(优化扩容)
        List<Integer> arrayList2 = new ArrayList<>(20);

        // 2. LinkedList
        List<String> linkedList = new LinkedList<>();

        // 3. 线程安全的CopyOnWriteArrayList
        List<String> safeList = new CopyOnWriteArrayList<>();

        // 4. 不可变List(Java 9+,元素不可增删改)
        List<String> immutableList = List.of("a", "b", "c");
    }
}

2. 核心操作(增删改查)

java 复制代码
List<String> list = new ArrayList<>();

// 增
list.add("Java");       // 末尾添加:[Java]
list.add(0, "Python");  // 索引0插入:[Python, Java]
list.addAll(Arrays.asList("C++", "Go"));  // 末尾添加集合:[Python, Java, C++, Go]

// 查
String elem = list.get(1);  // 获取索引1元素:Java
int index = list.indexOf("C++");  // 查找元素索引:2
boolean contains = list.contains("Go");  // 是否包含:true

// 改
String oldElem = list.set(2, "Rust");  // 替换索引2元素:[Python, Java, Rust, Go],oldElem=C++

// 删
list.remove(3);  // 删除索引3元素:[Python, Java, Rust]
list.remove("Python");  // 删除元素:[Java, Rust]

System.out.println(list);  // 输出:[Java, Rust]

3. 遍历 List(5 种常用方式)

java 复制代码
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "c"));

// 1. 普通for循环(基于索引)
for (int i = 0; i < list.size(); i++) {
    System.out.print(list.get(i) + " ");  // a b c
}

// 2. 增强for循环(foreach,推荐)
for (String s : list) {
    System.out.print(s + " ");
}

// 3. 迭代器(Iterator)- 支持遍历中删除元素
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String s = iterator.next();
    if (s.equals("b")) {
        iterator.remove();  // 安全删除(避免ConcurrentModificationException)
    }
    System.out.print(s + " ");  // a b c(删除后list变为[a, c])
}

// 4. Java 8+ forEach(函数式接口)
list.forEach(s -> System.out.print(s + " "));

// 5. Java 8+ Stream流遍历
list.stream().forEach(System.out::print);

4. 排序 List

List 支持自定义排序,核心用 Collections.sort()(旧版)或 List.sort()(Java 8+,推荐):

java 复制代码
List<Integer> numList = new ArrayList<>(Arrays.asList(3, 1, 4, 2));

// 1. 自然排序(元素需实现Comparable接口,如Integer、String)
numList.sort(Comparator.naturalOrder());  // 升序:[1, 2, 3, 4]

// 2. 逆序排序
numList.sort(Comparator.reverseOrder());  // 降序:[4, 3, 2, 1]

// 3. 自定义对象排序(以User为例)
class User {
    String name;
    int age;
    // 构造器、getter省略
}
List<User> userList = new ArrayList<>(Arrays.asList(
    new User("张三", 25),
    new User("李四", 20)
));
// 按年龄升序排序
userList.sort((u1, u2) -> u1.getAge() - u2.getAge());
// 或用Comparator.comparing(更简洁)
userList.sort(Comparator.comparingInt(User::getAge));

5. List 去重(保留顺序)

List 允许重复元素,去重常用 2 种方式:

java 复制代码
List<String> list = new ArrayList<>(Arrays.asList("a", "b", "a", "c"));

// 方式1:LinkedHashSet(保留插入顺序,去重)
List<String> distinctList1 = new ArrayList<>(new LinkedHashSet<>(list));
System.out.println(distinctList1);  // [a, b, c]

// 方式2:Java 8+ Stream.distinct()(保留顺序)
List<String> distinctList2 = list.stream().distinct().collect(Collectors.toList());

6. 并发安全问题与解决

ArrayListLinkedList 是线程不安全的,多线程修改时会抛 ConcurrentModificationException,解决方式:

java 复制代码
// 方式1:使用Collections.synchronizedList(加锁,效率一般)
List<String> syncList = Collections.synchronizedList(new ArrayList<>());

// 方式2:使用CopyOnWriteArrayList(读多写少,推荐)
List<String> safeList = new CopyOnWriteArrayList<>();

// 多线程操作示例
new Thread(() -> safeList.add("a")).start();
new Thread(() -> safeList.forEach(System.out::print)).start();

五、常见注意事项

  1. subList 视图特性subList(from, to) 返回原列表的子视图,修改子列表或原列表都会相互影响,且子列表依赖原列表存在(原列表被销毁后子列表不可用);
  2. 迭代器安全删除使用增强 for 循环或迭代器遍历的同时,不能用 list.remove()(会触发 fail-fast 机制抛异常),需用 Iterator.remove()
  3. 不可变 ListList.of() 创建的列表不可增删改,否则抛 UnsupportedOperationException
  4. ArrayList 初始化优化 :已知元素个数时,指定初始容量(如 new ArrayList<>(100)),避免频繁扩容
相关推荐
01漫游者1 分钟前
JavaScript函数与对象增强知识
开发语言·javascript·ecmascript
GottdesKrieges2 分钟前
OceanBase恢复常见问题
java·数据库·oceanbase
IGAn CTOU2 分钟前
Java高级开发进阶教程之系列
java·开发语言
leo825...6 分钟前
Claude Code Skills 清单(本地)
java·python·ai编程
csbysj20209 分钟前
SQL NULL 函数详解
开发语言
其实防守也摸鱼12 分钟前
CTF密码学综合教学指南--第三章
开发语言·网络·python·安全·网络安全·密码学
NGSI vimp12 分钟前
Java进阶——如何查看Java字节码
java·开发语言
We་ct1 小时前
深度剖析浏览器跨域问题
开发语言·前端·浏览器·跨域·cors·同源·浏览器跨域
身如柳絮随风扬1 小时前
多数据源切换实战:从业务场景到3种实现方案全解析
java·分布式·微服务
skywalk81631 小时前
在考虑双轨制,即在中文语法的基础上,加上数学公式的支持,这样像很多计算将更加简单方便,就像现在的小学数学课本里面一样,比如:定x=2*x + 1
开发语言