Java List 教程

更新于 2025-12-26

Jakob Jenkov 2020-02-29

Java 的 List 接口(java.util.List)表示一个有序的对象序列List 中的元素可以根据其在列表内部的顺序进行插入、访问、遍历和删除。这种数据结构之所以被称为“列表”,正是因为其元素具有明确的顺序。

List 中的每个元素都有一个索引。第一个元素的索引为 0,第二个为 1,依此类推。这个索引表示“距离列表开头有多少个元素”。因此,第一个元素距离列表开头 0 个位置——因为它就在开头。

你可以向 List 中添加任意 Java 对象。如果该 List 没有使用 Java 泛型(Generics) 进行类型限定,则甚至可以在同一个 List 中混合不同类型的对象(类)。不过,在实践中很少会这样做。

Java 的 List 接口是一个标准的 Java 接口,并且它是 Java Collection 接口的子类型,也就是说 List 继承自 Collection


List 与 Set 的区别

Java 的 List 接口与 Java Set 接口非常相似,因为它们都表示一组元素。但两者之间存在一些显著差异,这些差异也体现在各自接口提供的方法上。

  • 重复性List 允许同一个元素出现多次;而 Set 中每个元素只能出现一次。
  • 顺序性List 中的元素是有顺序的,可以按该顺序进行遍历;而 Set 不保证内部元素的任何顺序。

List 的实现类

由于 List 是一个接口,你需要实例化它的某个具体实现类才能使用。Java Collections API 提供了以下几种 List 实现:

  • java.util.ArrayList
  • java.util.LinkedList
  • java.util.Vector
  • java.util.Stack

其中,ArrayList 是最常用的实现

此外,在 java.util.concurrent 包中还提供了并发安全的 List 实现。

创建 List 实例

你可以通过实例化上述任一实现类来创建 List

List listA = new ArrayList();
List listB = new LinkedList();
List listC = new Vector();
List listD = new Stack();

通常情况下,你会使用 ArrayList,但在某些特定场景下,其他实现可能更合适。


泛型 List(Generic Lists)

默认情况下,你可以向 List 中放入任何 Object。但从 Java 5 开始,借助 Java 泛型(Generics),你可以限制 List 中允许插入的对象类型。

示例:

List<MyObject> list = new ArrayList<MyObject>();

List 只能插入 MyObject 类型的实例。访问和遍历时无需强制类型转换:

List<MyObject> list = new ArrayList<MyObject>();
list.add(new MyObject("First MyObject"));
MyObject myObject = list.get(0);

for (MyObject anObject : list) {
    // 对 anObject 执行操作...
}

如果不使用泛型,代码会变成这样:

List list = new ArrayList(); // 未指定泛型类型
list.add(new MyObject("First MyObject"));
MyObject myObject = (MyObject) list.get(0); // 需要强制转换

for (Object anObject : list) {
    MyObject theMyObject = (MyObject) anObject; // 需要强制转换
    // 对 anObject 执行操作...
}

可以看到,没有泛型时,每次从 List 中取出对象都需要显式转换为实际类型。

最佳实践:尽可能为 List 变量声明泛型类型。这有助于:

  • 避免插入错误类型的对象;
  • 无需强制转换即可安全地获取元素;
  • 提高代码可读性,让读者清楚知道 List 应包含什么类型。

除非有充分理由,否则不应省略泛型。

本文后续所有示例将尽可能使用泛型 List
更多关于 Java 泛型的信息,请参阅 Java 泛型教程


向 Java List 中插入元素

使用 add() 方法向 List 中插入元素:

List<String> listA = new ArrayList<>();
listA.add("element 1");
listA.add("element 2");
listA.add("element 3");

前三个 add() 调用会将 String 实例添加到列表末尾。

插入 null 值

Java List 允许插入 null 值:

Object element = null;
List<Object> list = new ArrayList<>();
list.add(element);

在指定索引处插入元素

List 接口提供了一个重载的 add(int index, E element) 方法,用于在指定位置插入元素:

list.add(0, "element 4");

如果列表中已有元素,原有元素会向后移动(索引 +1)。

将一个 List 的所有元素插入另一个 List

使用 addAll(Collection<? extends E> c) 方法:

List<String> listSource = new ArrayList<>();
listSource.add("123");
listSource.add("456");

List<String> listDest = new ArrayList<>();
listDest.addAll(listSource); // 将 source 中所有元素添加到 dest

注意:addAll() 接受 Collection 类型参数,因此你也可以传入 Set


从 Java List 中获取元素

通过索引使用 get(int index) 方法获取元素:

List<String> listA = new ArrayList<>();
listA.add("element 0");
listA.add("element 1");
listA.add("element 2");

String element0 = listA.get(0);
String element1 = listA.get(1);
String element2 = listA.get(2);

也可以按内部存储顺序遍历整个列表(见后文“遍历 List”部分)。


在 List 中查找元素

查找首次出现的位置:indexOf()

List<String> list = new ArrayList<>();
String element1 = "element 1";
String element2 = "element 2";
list.add(element1);
list.add(element2);

int index1 = list.indexOf(element1); // 0
int index2 = list.indexOf(element2); // 1

查找最后一次出现的位置:lastIndexOf()

list.add(element1); // 再次添加 element1
int lastIndex = list.lastIndexOf(element1); // 返回 2

判断 List 是否包含某元素:contains()

boolean containsElement = list.contains("element 1"); // true

contains() 方法内部会遍历列表,并使用元素的 equals() 方法进行比较。

也可以检查是否包含 null

list.add(null);
boolean hasNull = list.contains(null); // true

当参数为 null 时,contains() 使用 == 而非 equals() 进行比较。


从 Java List 中删除元素

按对象删除:remove(Object o)

List<String> list = new ArrayList<>();
String element = "first element";
list.add(element);
list.remove(element); // 删除该元素

按索引删除:remove(int index)

list.add("element 0");
list.add("element 1");
list.add("element 2");
list.remove(0); // 删除索引 0 处的元素
// 现在 list 包含 ["element 1", "element 2"]

删除后,后续元素索引自动前移。


清空 List(删除所有元素)

使用 clear() 方法:

List<String> list = new ArrayList<>();
list.add("object 1");
list.add("object 2");
list.clear(); // 清空列表

保留两个 List 的交集:retainAll()

retainAll(Collection<?> c) 会移除当前列表中不在参数集合中出现的所有元素,结果是两个集合的交集。

List<String> list = new ArrayList<>();
List<String> otherList = new ArrayList<>();

list.add("element 1");
list.add("element 2");
list.add("element 3");

otherList.add("element 1");
otherList.add("element 3");
otherList.add("element 4");

list.retainAll(otherList);
// list 现在只包含 ["element 1", "element 3"]

获取 List 大小

使用 size() 方法:

int size = list.size();

获取子列表:subList()

subList(int fromIndex, int toIndex) 返回原列表的一个视图,包含从 fromIndex(含)到 toIndex(不含)的元素。

List<String> list = new ArrayList<>();
list.add("element 1");
list.add("element 2");
list.add("element 3");
list.add("element 4");

List<String> sublist = list.subList(1, 3);
// sublist 包含 ["element 2", "element 3"]

注意:toIndex 对应的元素不包含在子列表中,类似于 String.substring()


将 List 转换为 Set

创建一个 Set 并将 List 中所有元素添加进去,自动去重:

List<String> list = new ArrayList<>();
list.add("element 1");
list.add("element 2");
list.add("element 3");
list.add("element 3"); // 重复

Set<String> set = new HashSet<>();
set.addAll(list);
// set 包含 {"element 1", "element 2", "element 3"}

将 List 转换为数组

转换为 Object[]

Object[] objects = list.toArray();

转换为指定类型数组

String[] strings = list.toArray(new String[0]);

即使传入长度为 0 的数组,返回的数组也会包含所有元素。


将数组转换为 List

使用 Arrays.asList()

String[] values = {"one", "two", "three"};
List<String> list = Arrays.asList(values);

注意:Arrays.asList() 返回的是固定大小的列表,不支持 add()remove() 操作。如需可变列表,应包装为 new ArrayList<>(Arrays.asList(...))


对 List 进行排序

使用 Collections.sort() 方法。

排序实现了 Comparable 接口的对象

例如 String

List<String> list = new ArrayList<>();
list.add("c");
list.add("b");
list.add("a");
Collections.sort(list); // 按自然顺序排序:["a", "b", "c"]

使用 Comparator 自定义排序

适用于未实现 Comparable 或需要自定义顺序的情况。

假设有一个 Car 类:

public class Car {
    public String brand;
    public String numberPlate;
    public int noOfDoors;
    
    public Car(String brand, String numberPlate, int noOfDoors) {
        this.brand = brand;
        this.numberPlate = numberPlate;
        this.noOfDoors = noOfDoors;
    }
}

按品牌排序:

List<Car> list = new ArrayList<>();
list.add(new Car("Volvo V40", "XYZ 201845", 5));
list.add(new Car("Citroen C1", "ABC 164521", 4));
list.add(new Car("Dodge Ram", "KLM 845990", 2));

Comparator<Car> carBrandComparator = new Comparator<Car>() {
    @Override
    public int compare(Car car1, Car car2) {
        return car1.brand.compareTo(car2.brand);
    }
};

Collections.sort(list, carBrandComparator);

使用 Lambda 表达式简化

Comparator<Car> byBrand = (c1, c2) -> c1.brand.compareTo(c2.brand);
Comparator<Car> byPlate = (c1, c2) -> c1.numberPlate.compareTo(c2.numberPlate);
Comparator<Car> byDoors = (c1, c2) -> c1.noOfDoors - c2.noOfDoors;

Collections.sort(list, byBrand);
Collections.sort(list, byPlate);
Collections.sort(list, byDoors);

遍历 List

有四种常见方式:

1. 使用 Iterator

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String element = iterator.next();
    // 处理 element
}

2. 使用 for-each 循环(推荐)

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

3. 使用传统 for 循环(带索引)

for (int i = 0; i < list.size(); i++) {
    String element = list.get(i);
    // 处理 element
}

4. 使用 Java Stream API

list.stream().forEach(element -> {
    System.out.println(element);
});

Stream API 还支持过滤、映射、聚合等高级操作。详见 Java Stream API 教程


更多细节请查阅 JavaDoc

本文仅涵盖最常用的操作(增删改查、遍历、排序等)。如需了解全部功能,请参考官方 Java List 接口文档(JavaDoc)