目录

一、引言

二、List接口概述

1.常用方法

2.实现List的主要类

2.1ArrayList

2.2LinkedList

2.3Vector

3.三者对比

三、List的遍历与去重

 1.List 的三种主要遍历方式

 1.1.普通 for 循环

 1.2.增强型 for 循环

 1.3.使用 Iterator

2.List去重方法

2.1.利用 HashSet 或 LinkedHashSet

2.2.Java 8+ 使用 Stream.distinct()

四、结语


一、引言


在Java中,List是java.util包下的一个接口,属于Java集合框架的一部分。它允许存储和操作有序的、可重复的对象序列。本文将详细介绍List接口、常用的方法、以及实现List接口的几个主要类(如ArrayList、LinkedList、Vector)。

以下是一个展示Java中List集合的思维导图:

二、List接口概述

List接口继承自Collection接口,提供了额外的功能来处理索引位置上的元素。与Set、Map不同,List允许包含重复的元素,并且可以通过索引来访问或修改特定位置的元素。

1.常用方法

add(E e):添加指定元素到列表末尾。
add(int index, E element):在指定索引处插入指定元素。
remove(int index):移除指定索引处的元素。
get(int index):获取指定索引处的元素。
set(int index, E element):替换指定索引处的元素。
size():返回列表中的元素数量。
isEmpty():判断列表是否为空。
contains(Object o):检查列表是否包含指定元素。
indexOf(Object o):返回指定元素首次出现的索引,如果不存在则返回-1。
lastIndexOf(Object o):返回指定元素最后一次出现的索引,如果不存在则返回-1。
subList(int fromIndex, int toIndex):获取从fromIndex(包括)到toIndex(不包括)之间的子列表

  // 创建一个ArrayList实例
        List<String> list = new ArrayList<>();

        // 添加元素
        list.add("Apple");
        list.add("Banana");
        list.add("Cherry");

        // 插入元素
        list.add(1, "Apricot");

        // 移除元素
        list.remove(2);

        // 获取元素
        System.out.println(list.get(0));  // 输出: Apple

        // 替换元素
        list.set(0, "Avocado");
        System.out.println(list.get(0));  // 输出: Avocado

        // 其他方法示例
        System.out.println(list.size());       // 输出: 3
        System.out.println(list.isEmpty());    // 输出: false
        System.out.println(list.contains("Banana"));  // 输出: true
        System.out.println(list.indexOf("Cherry"));   // 输出: 2
        System.out.println(list.lastIndexOf("Cherry"));  // 输出: 2
        System.out.println(list.subList(0, 2));         // 输出: [Avocado, Banana]
    
2.实现List的主要类
2.1ArrayList

ArrayList是最常用的List实现之一,它基于动态数组实现,支持随机访问,查询效率高,但插入和删除效率较低。
特点
支持快速随机访问。
非线程安全。
初始容量为10,每次扩容时增长50%。
使用场景
适用于频繁读取而不经常修改的数据集合。

示例代码

        // 创建并初始化ArrayList
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);

        // 访问元素
        for (int i = 0; i < numbers.size(); i++) {
            System.out.println(numbers.get(i));
        }

        // 修改元素
        numbers.set(1, 20);
        System.out.println(numbers);  // 输出: [1, 20, 3]

        // 删除元素
        numbers.remove(2);
        System.out.println(numbers);  // 输出: [1, 20]
2.2LinkedList

LinkedList是另一个重要的List实现,它基于双向链表实现,对于插入和删除操作具有较高的性能,但对于随机访问效率较低。
特点
支持高效的插入和删除操作。
非线程安全。
可以作为堆栈、队列或双端队列使用。
使用场景
适用于频繁进行插入和删除操作的数据集合。

示例代码

        // 创建并初始化LinkedList
        LinkedList<Character> characters = new LinkedList<>();
        characters.add('A');
        characters.add('B');
        characters.add('C');

        // 访问元素
        for (char c : characters) {
            System.out.print(c + " ");
        }
        System.out.println();  // 输出: A B C 

        // 在头部插入元素
        characters.addFirst('Z');
        System.out.println(characters);  // 输出: [Z, A, B, C]

        // 在尾部插入元素
        characters.addLast('D');
        System.out.println(characters);  // 输出: [Z, A, B, C, D]

        // 删除元素
        characters.removeFirst();
        characters.removeLast();
        System.out.println(characters);  // 输出: [A, B, C]
2.3Vector

早期线程安全集合类,通过方法级synchronized实现同步。默认扩容增长一倍。

特点

线程安全

同步锁导致并发效率低下(方法都使用了 synchronized)

性能低(主要用于同步开销)

遗留类,不推荐使用

示例代码

        // 创建 Vector
        List<String> vector = new Vector<>();

        // 添加元素
        vector.add("Java");
        vector.add("Python");
        vector.add("C++");

        // 插入元素
        vector.add(1, "JavaScript");

        // 输出结果
        System.out.println(vector);  // 输出: [Java, JavaScript, Python, C++]

        // 删除元素
        vector.remove(2);

        // 遍历
        for (String lang : vector) {
            System.out.println(lang);
        }
3.三者对比

三、List的遍历与去重

 1.List 的三种主要遍历方式
 1.1.普通 for 循环

 适用于需要访问索引的场景。

List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");

for (int i = 0; i < list.size(); i++) {
    System.out.println("Index: " + i + ", Value: " + list.get(i));
}

优点
可以灵活控制索引。
支持随机访问(适合 ArrayList)。
缺点
对于 LinkedList 来说效率较低(因为每次都要从头开始查找元素)。

 1.2.增强型 for 循环

语法简洁,适用于只需要获取元素的情况。

List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");

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

优点:
简洁易读。
适用于所有实现了 Iterable 接口的集合类。
缺点:
无法获取索引。
不能修改集合结构(如删除元素会抛出异常)。

 1.3.使用 Iterator

可以安全地在遍历时进行删除操作。

Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
    String item = iterator.next();
    if ("B".equals(item)) {
        iterator.remove();  // 安全删除
    }
}

优点:
支持在遍历过程中安全删除元素。
更加通用,适用于各种集合类型。

2.List去重方法

Java 中有多种方式可以实现 List 去重,下面是几种常见的方式:

2.1.利用 HashSet 或 LinkedHashSet

使用 HashSet(不保留顺序):

List<Integer> list = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
List<Integer> uniqueList = new ArrayList<>(new HashSet<>(list));
System.out.println(uniqueList);  // 输出顺序可能不同

使用 LinkedHashSet(保留插入顺序):

List<Integer> list = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
List<Integer> uniqueList = new ArrayList<>(new LinkedHashSet<>(list));
System.out.println(uniqueList);  // 输出: [1, 2, 3, 4, 5]

说明:

HashSet 和 LinkedHashSet 虽然常用于去重,但它们底层确实基于 HashMap 和 LinkedHashMap 实现的。也就是说,你给 List 去重时,实际上是借助了 Map 的特性来实现的。具体原因这里不做详细说明,需要的同学请关注我后续的文章。

2.2.Java 8+ 使用 Stream.distinct()
List<Integer> list = Arrays.asList(1, 2, 2, 3, 4, 4, 5);
List<Integer> uniqueList = list.stream().distinct().collect(Collectors.toList());
System.out.println(uniqueList);

说明:
distinct() 方法依赖于对象的 equals() 和 hashCode() 方法。
如果是自定义对象,请确保正确重写这两个方法。

四、结语

List 作为 Java 集合框架中最基础、最常用的数据结构之一,贯穿于几乎所有的 Java 应用开发中。掌握 List 的核心接口、常用实现类(如 ArrayList、LinkedList、Vector)、遍历方式和去重技巧,不仅有助于写出更高效、清晰的代码,也能帮助我们在面对复杂业务逻辑时做出更合理的技术选型。
在实际开发中,理解不同 List 实现的底层原理和适用场景,是写出高性能程序的关键。同时,结合 Set 和 Map 的使用,可以更好地处理唯一性、顺序性和映射关系等常见需求。
希望本文能为你深入理解 Java 中的 List 集合提供清晰的思路和实用的指导。无论你是刚入门的新手,还是有一定经验的开发者,集合框架始终是值得反复学习和实践的重要内容。持续深耕,才能在实际项目中游刃有余。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐