ZetCode

Java Collections.replaceAll 方法

上次修改时间:2025 年 4 月 20 日

Collections.replaceAll 方法是 Java Collections 框架中的一个实用方法。 它将 List 中指定值的所有出现都替换为另一个值。 此方法提供了一种方便的方式来对列表进行批量替换。

该方法定义在 java.util.Collections 类中。 它适用于任何 List 实现,并在线性时间内执行替换。 如果至少进行了一次替换,该方法将返回 true。

Collections.replaceAll 概述

replaceAll 方法签名是:public static <T> boolean replaceAll(List<T> list, T oldVal, T newVal)。 它接受三个参数:要修改的列表、要替换的值和新值。

该方法从头到尾扫描列表。 对于每个等于 oldVal(使用 equals)的元素,它用 newVal 替换它。 替换是就地完成的,修改原始列表。

基本 replaceAll 示例

此示例演示了 Collections.replaceAll 的基本用法。 我们创建一个字符串列表,并将所有出现的 "Apple" 替换为 "Orange"。 该示例显示了替换前后的列表。

BasicReplaceAll.java
package com.zetcode;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class BasicReplaceAll {

    public static void main(String[] args) {
        
        List<String> fruits = Arrays.asList(
            "Apple", "Banana", "Apple", "Cherry", "Apple");
        
        System.out.println("Original list: " + fruits);
        
        boolean changed = Collections.replaceAll(fruits, "Apple", "Orange");
        
        System.out.println("Modified list: " + fruits);
        System.out.println("Replacements made: " + changed);
    }
}

在此代码中,我们从一个包含三个 "Apple" 元素的列表开始。 在调用 replaceAll 之后,所有 "Apple" 元素都将替换为 "Orange"。 该方法返回 true,因为发生了替换。

输出显示了列表转换。 这是 replaceAll 最简单的用例,演示了其基本功能。

replaceAll 与 Integer 列表

此示例显示了 Collections.replaceAll 与 Integer 列表一起使用。 我们将所有数字 5 的出现替换为 50。 该示例还演示了未发生替换时的返回值。

IntegerReplaceAll.java
package com.zetcode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class IntegerReplaceAll {

    public static void main(String[] args) {
        
        List<Integer> numbers = new ArrayList<>();
        Collections.addAll(numbers, 1, 5, 3, 5, 7, 5);
        
        System.out.println("Original numbers: " + numbers);
        
        // Replace 5 with 50
        boolean changed1 = Collections.replaceAll(numbers, 5, 50);
        System.out.println("After first replacement: " + numbers);
        System.out.println("Replacements made: " + changed1);
        
        // Try replacing 99 (not present)
        boolean changed2 = Collections.replaceAll(numbers, 99, 100);
        System.out.println("After second replacement: " + numbers);
        System.out.println("Replacements made: " + changed2);
    }
}

此示例演示了 replaceAll 与数值的使用。 第一个调用成功地将所有 5 替换为 50。 第二个调用尝试替换 99,而列表中没有 99,因此没有发生更改。

输出显示了该方法在这两种情况下的行为。 返回值指示是否执行了任何替换。

replaceAll 与自定义对象

此示例演示了将 Collections.replaceAll 与自定义对象一起使用。 我们创建一个简单的 Person 类,并将一个 Person 的所有实例替换为另一个 Person。 该示例重点介绍了正确实现 equals 的重要性。

CustomObjectReplaceAll.java
package com.zetcode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class Person {
    private String name;
    private int age;
    
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return age == person.age && name.equals(person.name);
    }
    
    @Override
    public String toString() {
        return name + "(" + age + ")";
    }
}

public class CustomObjectReplaceAll {

    public static void main(String[] args) {
        
        List<Person> people = new ArrayList<>();
        Collections.addAll(people,
            new Person("Alice", 25),
            new Person("Bob", 30),
            new Person("Alice", 25),
            new Person("Charlie", 35)
        );
        
        System.out.println("Original list: " + people);
        
        Person oldPerson = new Person("Alice", 25);
        Person newPerson = new Person("Alex", 26);
        
        boolean changed = Collections.replaceAll(people, oldPerson, newPerson);
        
        System.out.println("Modified list: " + people);
        System.out.println("Replacements made: " + changed);
    }
}

此示例显示了当自定义对象正确实现 equals 时,replaceAll 可以使用它们。 我们将所有 Alice (25) 实例替换为 Alex (26)。 equals 方法比较名称和年龄字段。

输出演示了 Person 对象的替换。 如果没有正确的 equals 实现,该方法将找不到要替换的匹配项。

replaceAll 与 Null 值

此示例探讨了 Collections.replaceAll 如何处理 null 值。 我们创建一个包含 null 元素的列表,并演示将它们替换为非 null 值,反之亦然。

NullReplaceAll.java
package com.zetcode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class NullReplaceAll {

    public static void main(String[] args) {
        
        List<String> items = new ArrayList<>();
        Collections.addAll(items, "A", null, "B", null, "C");
        
        System.out.println("Original list: " + items);
        
        // Replace null with "X"
        boolean changed1 = Collections.replaceAll(items, null, "X");
        System.out.println("After replacing null with X: " + items);
        System.out.println("Replacements made: " + changed1);
        
        // Replace "B" with null
        boolean changed2 = Collections.replaceAll(items, "B", null);
        System.out.println("After replacing B with null: " + items);
        System.out.println("Replacements made: " + changed2);
    }
}

此示例显示了 replaceAll 可以将 null 值作为 oldVal 和 newVal 参数处理。 我们首先将所有 null 替换为 "X",然后将 "B" 替换为 null。

输出演示了 null 处理按预期工作。 该方法既可以通过替换它们来删除 null,也可以引入 null 作为替换。

不区分大小写的 replaceAll

此示例演示了使用 Collections.replaceAll 进行不区分大小写的替换。 由于该方法使用 equals 进行比较,因此我们需要一个针对不区分大小写匹配的解决方法。

CaseInsensitiveReplaceAll.java
package com.zetcode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CaseInsensitiveReplaceAll {

    public static void main(String[] args) {
        
        List<String> words = new ArrayList<>();
        Collections.addAll(words, "Apple", "apple", "APPLE", "banana");
        
        System.out.println("Original list: " + words);
        
        // Traditional replaceAll is case-sensitive
        boolean changed1 = Collections.replaceAll(words, "apple", "orange");
        System.out.println("After case-sensitive replacement: " + words);
        System.out.println("Replacements made: " + changed1);
        
        // Case-insensitive replacement
        String target = "apple";
        String replacement = "orange";
        words.replaceAll(s -> s.equalsIgnoreCase(target) ? replacement : s);
        
        System.out.println("After case-insensitive replacement: " + words);
    }
}

此示例显示了两种方法。 首先,标准的 replaceAll,区分大小写。 然后,我们使用 List.replaceAll 和一个 lambda 表达式进行不区分大小写的匹配。

输出演示了这两种方法之间的区别。 对于不区分大小写的操作,lambda 方法比 Collections.replaceAll 更灵活。

replaceAll vs List.replaceAll

此示例比较了 Collections.replaceAll 与 Java 8 的 List.replaceAll。 尽管相似,但它们具有不同的功能。 该示例并排演示了这两种方法。

ReplaceAllComparison.java
package com.zetcode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ReplaceAllComparison {

    public static void main(String[] args) {
        
        List<Integer> numbers = new ArrayList<>();
        Collections.addAll(numbers, 1, 2, 3, 4, 5);
        
        System.out.println("Original list: " + numbers);
        
        // Collections.replaceAll - replace specific value
        Collections.replaceAll(numbers, 3, 30);
        System.out.println("After Collections.replaceAll: " + numbers);
        
        // List.replaceAll - transform all elements
        numbers.replaceAll(n -> n * 10);
        System.out.println("After List.replaceAll: " + numbers);
    }
}

此示例重点介绍了这两种方法之间的主要区别。 Collections.replaceAll 替换特定值,而 List.replaceAll 可以通过 UnaryOperator 转换所有元素。

输出显示了每种方法如何以不同的方式修改列表。 选择 Collections.replaceAll 进行简单的值替换,选择 List.replaceAll 进行更复杂的转换。

性能注意事项

此示例检查 Collections.replaceAll 的性能特征。 我们创建一个大型列表并测量替换所花费的时间。 该示例演示了它的线性时间复杂度。

ReplaceAllPerformance.java
package com.zetcode;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ReplaceAllPerformance {

    public static void main(String[] args) {
        
        final int SIZE = 1_000_000;
        List<Integer> numbers = new ArrayList<>(SIZE);
        
        // Fill the list with 1s, with a 5 at the end
        for (int i = 0; i < SIZE - 1; i++) {
            numbers.add(1);
        }
        numbers.add(5);
        
        long startTime = System.nanoTime();
        Collections.replaceAll(numbers, 1, 10);
        long endTime = System.nanoTime();
        
        System.out.println("Time taken: " + 
            (endTime - startTime) / 1_000_000 + " ms");
        System.out.println("Last element (unchanged): " + 
            numbers.get(numbers.size() - 1));
    }
}

此示例创建一个大型列表并测量将所有 1 替换为 10 所需的时间。 尽管列表很大,但该操作很快完成,这表明了 replaceAll 的 O(n) 时间复杂度。

输出显示了操作时间和确认最后一个元素 (5) 保持不变。 此测试有助于理解该方法的性能特征。

来源

Java Collections.replaceAll 文档

在本文中,我们深入探讨了 Java Collections.replaceAll 方法。 我们涵盖了基本用法、自定义对象、null 处理和性能考虑。 理解此方法有助于高效的列表修改。

作者

我叫 Jan Bodnar,是一位经验丰富的程序员,在这一领域拥有多年的经验。 我从 2007 年开始撰写编程文章,此后撰写了 1,400 多篇文章和八本电子书。 凭借八年以上的教学经验,我致力于分享我的知识并帮助他人掌握编程概念。

列出所有Java教程