当前位置:首页 > 后端开发 > 正文

java list怎么使用方法

Java List通过add()添加元素,get(index)获取,size()查长度,可用

Java中的Listjava.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!

注意事项与最佳实践

  1. 避免空指针异常

    java list怎么使用方法  第1张

    • 始终检查size()后再通过索引访问元素
    • 使用isEmpty()判断空列表而非size()==0
  2. 迭代器安全

    • 结构化修改(遍历时删除/添加)会导致ConcurrentModificationException
    • 解决方案:使用Iteratorremove()方法或改用for循环倒序删除
  3. 内存优化

    • ArrayList初始容量设为预计大小的120%可减少扩容次数
    • 高频插入/删除场景优先考虑LinkedList
  4. 线程安全方案选择

    • 读多写少: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循环倒序删除;③克隆新

0