Java List 使用详解:从入门到精通

发布于:2025-07-09 ⋅ 阅读:(19) ⋅ 点赞:(0)

一、List 基础概念

1.1 什么是 List?

List 就像是一个智能书架

  • 可以按顺序存放书籍(元素)
  • 每本书都有固定位置(索引)
  • 可以随时添加、取出或重新排列书籍
// 创建一个书架(List)
List<String> bookshelf = new ArrayList<>();

1.2 List 的核心特性

特性 说明 生活类比
有序性 元素按添加顺序存储 书架上的书按放入顺序排列
可重复 允许相同元素多次出现 同一本书可以有多个副本
索引访问 通过位置编号快速获取元素 通过书架编号找书
动态扩容 自动调整存储空间 智能书架自动扩展

1.3 List 家族成员

二、List 基本操作 

2.1 创建 List 的三种方式

// 方式1:标准创建(推荐)
List<String> fruits = new ArrayList<>();

// 方式2:快速初始化
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);

// 方式3:不可变列表(Java 9+)
List<String> colors = List.of("红", "绿", "蓝");

2.2 添加元素 - 丰富你的书架

fruits.add("苹果");     // 末尾添加
fruits.add(0, "香蕉");  // 指定位置插入
fruits.addAll(Arrays.asList("橙子", "葡萄")); // 批量添加

System.out.println(fruits); 
// 输出: [香蕉, 苹果, 橙子, 葡萄]

2.3 访问元素 - 查找书籍

// 获取单个元素
String firstFruit = fruits.get(0); // "香蕉"

// 检查元素是否存在
boolean hasApple = fruits.contains("苹果"); // true

// 查找元素位置
int appleIndex = fruits.indexOf("苹果"); // 1

2.4 修改元素 - 替换书籍

// 替换指定位置的元素
String oldFruit = fruits.set(1, "青苹果");
System.out.println("被替换的水果: " + oldFruit); // "苹果"

2.5 删除元素 - 清理书架

// 按索引删除
String removed = fruits.remove(0); // 删除"香蕉"

// 按元素值删除
boolean isRemoved = fruits.remove("葡萄"); // true

// 批量删除
fruits.removeAll(Arrays.asList("橙子", "青苹果"));

// 清空书架
fruits.clear();

三、遍历 List 的多种方式 

3.1 基础遍历方法

// 1. for循环(索引访问)
for (int i = 0; i < fruits.size(); i++) {
    System.out.println((i+1) + ". " + fruits.get(i));
}

// 2. 增强for循环
for (String fruit : fruits) {
    System.out.println(fruit);
}

3.2 使用迭代器

// 3. Iterator遍历
Iterator<String> iterator = fruits.iterator();
while (iterator.hasNext()) {
    String fruit = iterator.next();
    if (fruit.equals("葡萄")) {
        iterator.remove(); // 安全删除
    }
}

3.3 Java 8+ 高级遍历

// 4. forEach方法
fruits.forEach(fruit -> System.out.println(fruit));

// 5. 方法引用
fruits.forEach(System.out::println);

// 6. 并行流遍历(大数据量)
fruits.parallelStream().forEach(fruit -> {
    // 并行处理逻辑
});

3.4 遍历性能对比

遍历方式 10万元素耗时 适用场景
for循环 5ms 需要索引时
增强for 7ms 简单遍历
Iterator 8ms 需要删除元素时
forEach 10ms 函数式编程
并行流 3ms 大数据量处理

四、List 高级操作 

4.1 排序操作

List<Integer> numbers = Arrays.asList(5, 2, 9, 1, 3);

// 自然排序(升序)
Collections.sort(numbers);
// 输出: [1, 2, 3, 5, 9]

// 自定义排序(降序)
numbers.sort((a, b) -> b - a);
// 输出: [9, 5, 3, 2, 1]

// 对象排序
List<Book> books = new ArrayList<>();
books.add(new Book("Java编程", 99));
books.add(new Book("Python入门", 69));

books.sort(Comparator.comparing(Book::getPrice));

4.2 过滤与转换

// 过滤高价水果
List<String> expensiveFruits = fruits.stream()
    .filter(fruit -> fruit.length() > 2)
    .collect(Collectors.toList());

// 水果名称转大写
List<String> upperCaseFruits = fruits.stream()
    .map(String::toUpperCase)
    .collect(Collectors.toList());

4.3 数学统计

IntSummaryStatistics stats = numbers.stream()
    .mapToInt(Integer::intValue)
    .summaryStatistics();

System.out.println("最大值: " + stats.getMax());
System.out.println("最小值: " + stats.getMin());
System.out.println("平均值: " + stats.getAverage());
System.out.println("总数: " + stats.getSum());

4.4 列表转换

// List转数组
String[] fruitArray = fruits.toArray(new String[0]);

// 数组转List(不可修改)
List<String> fixedList = Arrays.asList(fruitArray);

// 数组转List(可修改)
List<String> modifiableList = new ArrayList<>(Arrays.asList(fruitArray));

五、ArrayList 深度解析 

5.1 内部结构

ArrayList 就像是一个智能伸缩书架

// 简化版ArrayList实现
public class SimpleArrayList<E> {
    private Object[] elements; // 存储元素的数组
    private int size;          // 当前元素数量
    
    public SimpleArrayList() {
        this.elements = new Object[10]; // 初始容量
    }
    
    public void add(E element) {
        // 当数组满时自动扩容
        if (size == elements.length) {
            Object[] newArray = new Object[elements.length * 2];
            System.arraycopy(elements, 0, newArray, 0, size);
            elements = newArray;
        }
        elements[size++] = element;
    }
}

5.2 扩容机制

5.3 性能特点

操作 时间复杂度 说明
get(index) O(1) 直接通过索引访问
add(element) O(1) 平均时间复杂度
add(index, element) O(n) 需要移动后续元素
remove(index) O(n) 需要移动后续元素
contains(element) O(n) 需要遍历查找

六、LinkedList 深度解析

6.1 内部结构

LinkedList 就像是一个带前后指针的书本链

// 简化版链表节点
class Node<E> {
    E item;         // 当前元素
    Node<E> next;   // 下一个节点
    Node<E> prev;   // 上一个节点
    
    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

6.2 操作原理

// 在指定位置插入元素
public void add(int index, E element) {
    // 1. 找到目标位置的节点
    Node<E> target = getNode(index);
    
    // 2. 创建新节点
    Node<E> newNode = new Node<>(target.prev, element, target);
    
    // 3. 调整前后节点指针
    target.prev.next = newNode;
    target.prev = newNode;
}

6.3 性能对比 ArrayList

操作 ArrayList LinkedList 适用场景
随机访问 ⚡️ 快 (O(1)) 🐢 慢 (O(n)) 需要频繁按索引访问
头部插入 🐢 慢 (O(n)) ⚡️ 快 (O(1)) 需要频繁在开头添加
尾部插入 ⚡️ 快 (O(1)) ⚡️ 快 (O(1)) 在末尾添加
中间插入 🐢 慢 (O(n)) ⚡️ 快 (O(1)) 需要频繁在中间插入
内存占用 较少(仅需存储元素) 较多(每个元素需要额外指针) 内存敏感场景

七、实战应用案例

7.1 学生成绩管理系统

class Student {
    private String name;
    private int score;
    // 构造方法、getter/setter省略
}

public class GradeSystem {
    private List<Student> students = new ArrayList<>();
    
    // 添加学生
    public void addStudent(Student student) {
        students.add(student);
    }
    
    // 按分数排序
    public void sortByScore() {
        students.sort(Comparator.comparingInt(Student::getScore).reversed());
    }
    
    // 查找前N名学生
    public List<Student> getTopStudents(int n) {
        return students.stream()
            .sorted(Comparator.comparingInt(Student::getScore).reversed())
            .limit(n)
            .collect(Collectors.toList());
    }
    
    // 统计分数分布
    public Map<String, Long> getScoreDistribution() {
        return students.stream()
            .collect(Collectors.groupingBy(
                s -> {
                    int score = s.getScore();
                    if (score >= 90) return "优秀";
                    if (score >= 80) return "良好";
                    if (score >= 60) return "及格";
                    return "不及格";
                },
                Collectors.counting()
            ));
    }
}

7.2 购物车实现

class CartItem {
    private String productId;
    private String name;
    private double price;
    private int quantity;
    // 构造方法、getter/setter省略
}

public class ShoppingCart {
    private List<CartItem> items = new LinkedList<>();
    
    // 添加商品
    public void addItem(CartItem newItem) {
        // 检查是否已存在
        for (CartItem item : items) {
            if (item.getProductId().equals(newItem.getProductId())) {
                item.setQuantity(item.getQuantity() + newItem.getQuantity());
                return;
            }
        }
        items.add(newItem);
    }
    
    // 更新数量
    public void updateQuantity(String productId, int newQuantity) {
        items.removeIf(item -> item.getProductId().equals(productId));
        if (newQuantity > 0) {
            items.add(new CartItem(productId, newQuantity));
        }
    }
    
    // 计算总价
    public double calculateTotal() {
        return items.stream()
            .mapToDouble(item -> item.getPrice() * item.getQuantity())
            .sum();
    }
    
    // 生成订单
    public Order checkout() {
        Order order = new Order();
        order.setItems(new ArrayList<>(items));
        order.setTotal(calculateTotal());
        items.clear();
        return order;
    }
}

八、最佳实践与性能优化

8.1 选择正确的 List 实现

场景 推荐实现 理由
读多写少 ArrayList 随机访问快
频繁增删 LinkedList 插入删除快
多线程环境 CopyOnWriteArrayList 线程安全
固定大小列表 Arrays.asList() 内存优化
不可变列表 List.of() 安全简洁

8.2 性能优化技巧

   预分配容量(减少扩容开销)

// 预计存储1000个元素
List<String> largeList = new ArrayList<>(1000);

       批量操作(减少方法调用) 

// 差: 多次调用add
for (String item : items) {
    list.add(item);
}

// 好: 批量添加
list.addAll(items);

   

避免在循环中调用size

// 差: 每次循环都调用size()
for (int i = 0; i < list.size(); i++) {
    // ...
}

// 好: 缓存size值
int size = list.size();
for (int i = 0; i < size; i++) {
    // ...
}

使用subList视图

// 创建子列表视图(不复制数据)
List<String> sub = list.subList(0, 5);

九、常见问题与解决方案 (30分钟)

 ConcurrentModificationException

问题:遍历时修改集合

List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
for (String s : list) {
    if ("B".equals(s)) {
        list.remove(s); // 抛出异常
    }
}

解决方案

// 1. 使用Iterator的remove方法
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    String s = it.next();
    if ("B".equals(s)) {
        it.remove(); // 安全删除
    }
}

// 2. 使用Java 8+ removeIf
list.removeIf("B"::equals);

// 3. 创建副本遍历
new ArrayList<>(list).forEach(s -> {
    if ("B".equals(s)) {
        list.remove(s);
    }
});

性能陷阱:LinkedList的随机访问

问题

LinkedList<Integer> list = new LinkedList<>();
// 填充数据...

// 随机访问性能差
for (int i = 0; i < list.size(); i++) {
    Integer value = list.get(i); // O(n)操作
}

解决方案

// 1. 使用迭代器
Iterator<Integer> it = list.iterator();
while (it.hasNext()) {
    Integer value = it.next();
}

// 2. 使用增强for循环
for (Integer value : list) {
    // ...
}

// 3. 转换为ArrayList(只读场景)
List<Integer> arrayList = new ArrayList<>(list);

 对象相等性判断

问题:自定义对象在List中的行为

解决方案

class Person {
    String name;
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return Objects.equals(name, person.name);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

十、总结与进阶学习 

 List 知识体系总结


网站公告

今日签到

点亮在社区的每一天
去签到