Java List 接口详解:从基础到实战

1. 引言

List 是 Java 集合框架中最常用的接口之一,它表示一个有序、可重复的元素集合。无论是日常开发还是面试考察,List 都是绕不开的核心知识点。本文将从接口定义、常用实现类、遍历方式到实战注意事项,系统梳理 Java List 接口的方方面面。

2. List 接口概述

List 接口继承自 Collection 接口,位于 java.util 包中。它允许存储重复元素,并且每个元素都有对应的索引位置,可以通过索引精确访问元素。与 Set 不同,List 保持了元素的插入顺序。

List 接口的主要特点包括:

  • 有序性:元素按照插入顺序排列,可通过索引访问。
  • 可重复:允许存储相同的元素。
  • 允许 null:大多数实现类允许存储 null 值。
  • 索引访问:支持通过下标快速定位元素。

3. 常用实现类

List 接口有多个实现类,其中最常用的是 ArrayList、LinkedList 和 Vector。三者底层结构不同,适用场景也各有侧重。

3.1 ArrayList

ArrayList 基于动态数组实现,支持随机访问,查询效率高,但插入和删除元素时可能需要移动后续元素,性能相对较低。它是日常开发中使用最频繁的 List 实现。

List<String> list = new ArrayList<>();
list.add("Java");
list.add("Python");
list.add("Go");
System.out.println(list.get(1)); // 输出 Python

3.2 LinkedList

LinkedList 基于双向链表实现,插入和删除元素效率高,但随机访问性能较差。它同时实现了 List 和 Deque 接口,因此也可以作为队列或双端队列使用。

List<Integer> numbers = new LinkedList<>();
numbers.add(10);
numbers.add(20);
numbers.addFirst(5); // 头部插入
System.out.println(numbers); // 输出 [5, 10, 20]

3.3 Vector

Vector 是早期版本的线程安全实现,方法使用 synchronized 修饰。由于同步开销较大,在单线程场景下性能不如 ArrayList,目前已经较少使用。若需要线程安全的 List,推荐使用 Collections.synchronizedList 或 CopyOnWriteArrayList。

4. 常用方法

List 接口提供了丰富的方法用于元素操作,下面按功能分类介绍。

4.1 添加元素

  • add(E e):在列表末尾追加元素。
  • add(int index, E e):在指定索引位置插入元素。
  • addAll(Collection c):将另一个集合的所有元素追加到末尾。

4.2 删除元素

  • remove(int index):删除指定索引位置的元素。
  • remove(Object o):删除第一个匹配的指定元素。
  • clear():清空列表中的所有元素。

4.3 查询与修改

  • get(int index):获取指定索引位置的元素。
  • set(int index, E e):替换指定索引位置的元素。
  • size():返回列表中的元素个数。
  • contains(Object o):判断列表是否包含指定元素。
  • indexOf(Object o):返回指定元素首次出现的索引。

5. 遍历方式

List 的遍历方式多种多样,常见的有 for 循环、增强 for、迭代器和 Stream 流。不同方式在简洁性和灵活性上各有优劣。

5.1 普通 for 循环

for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

5.2 增强 for 循环

for (String item : list) {
    System.out.println(item);
}

5.3 迭代器遍历

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    System.out.println(iterator.next());
}

5.4 Stream 流遍历

list.stream().forEach(System.out::println);

6. 排序与去重

对 List 进行排序和去重是开发中的高频操作。排序可以使用 Collections.sort 或 List.sort 方法,去重则常借助 Stream 的 distinct 方法。

List<Integer> scores = new ArrayList<>(Arrays.asList(88, 92, 75, 88, 60));
// 排序
scores.sort(Integer::compareTo);
System.out.println(scores); // 输出 [60, 75, 88, 88, 92]
// 去重
List<Integer> unique = scores.stream().distinct().collect(Collectors.toList());
System.out.println(unique); // 输出 [60, 75, 88, 92]

7. 线程安全与并发场景

ArrayList 和 LinkedList 都不是线程安全的。在多线程环境下,如果多个线程同时修改同一个 List,可能引发数据不一致或 ConcurrentModificationException。常用的解决方案有以下几种:

  • Collections.synchronizedList:对 List 进行同步包装。
  • CopyOnWriteArrayList:读写分离,适合读多写少的场景。
  • Vector:传统线程安全实现,但性能较差。

8. 常见问题与注意事项

在使用 List 时,有几个容易踩坑的地方需要特别留意。

8.1 遍历时删除元素

在增强 for 循环中直接调用 remove 方法会抛出 ConcurrentModificationException,应使用迭代器的 remove 方法或 Stream 过滤。

// 错误示例
for (String item : list) {
    if ("Java".equals(item)) {
        list.remove(item); // 抛出异常
    }
}
// 正确示例
list.removeIf("Java"::equals);

8.2 Arrays.asList 的陷阱

Arrays.asList 返回的是固定长度的列表,不能调用 add 和 remove 方法,否则会抛出 UnsupportedOperationException。

List<String> fixed = Arrays.asList("A", "B");
fixed.add("C"); // 抛出 UnsupportedOperationException

8.3 索引越界

访问不存在的索引会抛出 IndexOutOfBoundsException,建议在访问前先判断索引范围。

9. 总结

List 是 Java 集合框架中最重要的接口之一,掌握它的实现原理、常用方法和遍历方式,是写出高质量 Java 代码的基础。在实际开发中,应根据具体场景选择合适的实现类:查询频繁选 ArrayList,插入删除频繁选 LinkedList,并发场景则考虑线程安全方案。希望本文能帮助你更系统地理解 Java List 接口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值