Java Collections.nCopies 方法
上次修改时间:2025 年 4 月 20 日
Collections.nCopies 方法是 Java Collections Framework 中的一个实用方法。 它创建一个包含单个元素的多个副本的不可变列表。 当您需要一个具有重复值的列表时,这很有用。
该方法返回一个包含指定对象的 n 个副本的列表。 该列表是不可变的,这意味着它的大小和元素无法更改。 列表中的所有元素都引用同一个对象。
Collections.nCopies 概述
nCopies 方法是 java.util.Collections 类的一部分。 这是一个静态工厂方法,用于创建一种特殊的 List 实现。 返回的列表是节省空间的,因为它只存储一个元素引用。
该方法的签名是:static <T> List<T> nCopies(int n, T o)。 第一个参数是副本的数量,第二个参数是要重复的元素。 该列表是可序列化的,并实现了 RandomAccess 以实现高效访问。
基本 nCopies 示例
此示例演示了 nCopies 的最简单用法。 我们创建一个包含字符串 "Hello" 的五个副本的列表。 生成的列表是不可变的,无法修改。
package com.zetcode;
import java.util.Collections;
import java.util.List;
public class BasicNCopies {
public static void main(String[] args) {
List<String> greetings = Collections.nCopies(5, "Hello");
System.out.println("List size: " + greetings.size());
System.out.println("List contents: " + greetings);
try {
greetings.add("Hi"); // Will throw exception
} catch (UnsupportedOperationException e) {
System.out.println("\nCannot modify nCopies list: " + e);
}
}
}
此代码创建一个包含五个 "Hello" 字符串的不可变列表。 列表的大小在创建时是固定的。 尝试修改列表会抛出 UnsupportedOperationException 异常。
输出显示了列表内容并演示了它的不变性。 这对于创建常量列表或默认值集合很有用。
创建初始化列表
nCopies 可用于初始化可变列表。 通过将不可变列表传递给构造函数,我们可以创建一个可变副本。 这比在循环中添加元素更有效。
package com.zetcode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class InitializeList {
public static void main(String[] args) {
// Create immutable list with 10 zeros
List<Integer> immutableZeros = Collections.nCopies(10, 0);
// Create mutable list from immutable one
List<Integer> mutableZeros = new ArrayList<>(immutableZeros);
System.out.println("Initial list: " + mutableZeros);
// Now we can modify it
mutableZeros.set(5, 99);
mutableZeros.add(100);
System.out.println("Modified list: " + mutableZeros);
}
}
此示例演示了如何使用 nCopies 进行列表初始化。 我们首先创建一个由零组成的不可变列表,然后使用它来构造一个可变的 ArrayList。 然后可以根据需要修改可变列表。
这种方法比使用循环进行初始化更有效,尤其是对于大型列表。 它清楚地表达了创建具有默认值的列表的意图。
使用自定义对象
nCopies 适用于任何对象类型,包括自定义类。 生成列表中的所有元素都将引用同一个对象实例。 在使用可变对象时,理解这一点很重要。
package com.zetcode;
import java.util.Collections;
import java.util.List;
class Person {
private String name;
public Person(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
public class CustomObjects {
public static void main(String[] args) {
Person original = new Person("John");
List<Person> people = Collections.nCopies(3, original);
System.out.println("Original list: " + people);
// Modify the original object
original.setName("Jane");
System.out.println("After modification: " + people);
}
}
此示例演示了将 nCopies 与自定义 Person 类一起使用。 该列表包含对同一 Person 对象的多个引用。 更改原始对象会影响列表中的所有元素。
在使用可变对象时,理解这种行为很重要。 对于不可变对象(例如字符串),这种共享是安全的且节省内存。
将 nCopies 与 Streams 一起使用
Java 8 流可以与 nCopies 列表一起使用。 虽然该列表是不可变的,但我们可以使用流操作处理其元素。 此示例显示了过滤和映射操作。
package com.zetcode;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class NCopiesStreams {
public static void main(String[] args) {
List<Integer> numbers = Collections.nCopies(10, 5);
System.out.println("Original list: " + numbers);
// Process with stream
List<Integer> processed = numbers.stream()
.map(n -> n * 2) // Double each number
.filter(n -> n > 5) // Filter numbers > 5
.collect(Collectors.toList());
System.out.println("Processed list: " + processed);
}
}
此示例使用 nCopies 创建一个由十个五组成的列表,然后使用流对其进行处理。 流操作将每个数字加倍,并过滤掉大于五的数字。 结果是一个新的可变列表。
Streams 提供了一种强大的方式来处理 nCopies 列表而无需修改它们。 这对于重复值的转换和计算很有用。
性能注意事项
nCopies 对于大型列表来说是非常节省内存的。 无论列表大小如何,它只存储一个元素引用。 此示例比较了 nCopies 和常规列表创建之间的内存使用情况。
package com.zetcode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class PerformanceTest {
public static void main(String[] args) {
final int SIZE = 1_000_000;
// Using nCopies
long start = System.nanoTime();
List<String> nCopyList = Collections.nCopies(SIZE, "item");
long nCopyTime = System.nanoTime() - start;
// Using ArrayList
start = System.nanoTime();
List<String> arrayList = new ArrayList<>(SIZE);
for (int i = 0; i < SIZE; i++) {
arrayList.add("item");
}
long arrayListTime = System.nanoTime() - start;
System.out.println("nCopies creation time (ms): " +
nCopyTime / 1_000_000);
System.out.println("ArrayList creation time (ms): " +
arrayListTime / 1_000_000);
System.out.println("nCopies memory efficient: " +
(nCopyList.size() == arrayList.size()));
}
}
此示例演示了 nCopies 的性能优势。 使用 nCopies 创建一个包含一百万个元素的列表比手动填充 ArrayList 快得多。 它也更节省内存。
输出显示了两种方法之间的时间差异。 对于大型的、只读的相同元素列表,nCopies 是更好的选择。
数据结构中的 nCopies
nCopies 可用于初始化更复杂的数据结构。 此示例显示了创建列表的列表,其中每个子列表包含重复值。 这种模式对于矩阵初始化很有用。
package com.zetcode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MatrixInitialization {
public static void main(String[] args) {
final int ROWS = 3;
final int COLS = 4;
final int INIT_VALUE = 0;
// Create list of lists using nCopies
List<List<Integer>> matrix = new ArrayList<>(
Collections.nCopies(ROWS,
new ArrayList<>(Collections.nCopies(COLS, INIT_VALUE))
);
System.out.println("Initial matrix:");
matrix.forEach(row -> System.out.println(row));
// Modify one element
matrix.get(1).set(2, 99);
System.out.println("\nModified matrix:");
matrix.forEach(row -> System.out.println(row));
}
}
此示例使用嵌套的 nCopies 创建一个用零初始化的 3x4 矩阵。 外部列表包含对同一内部列表的引用,因此修改一行会影响所有行。 这演示了 nCopies 的强大功能和潜在缺陷。
对于正确的矩阵初始化,您需要创建不同的内部列表。 此示例用作对嵌套结构中共享引用的警告。
nCopies 的替代方案
Java 8 引入了 Stream.generate 作为 nCopies 的替代方案。 此示例比较了创建具有重复元素的列表的两种方法。 每种方法都有不同的特性和用例。
package com.zetcode;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StreamAlternative {
public static void main(String[] args) {
// Using nCopies
List<String> nCopyList = Collections.nCopies(5, "Java");
System.out.println("nCopies result: " + nCopyList);
// Using Stream.generate
List<String> streamList = Stream.generate(() -> "Java")
.limit(5)
.collect(Collectors.toList());
System.out.println("Stream result: " + streamList);
// Performance comparison
long start = System.nanoTime();
Collections.nCopies(1_000_000, "Java");
long nCopyTime = System.nanoTime() - start;
start = System.nanoTime();
Stream.generate(() -> "Java").limit(1_000_000).collect(Collectors.toList());
long streamTime = System.nanoTime() - start;
System.out.println("\nnCopies time (ms): " + nCopyTime / 1_000_000);
System.out.println("Stream time (ms): " + streamTime / 1_000_000);
}
}
此示例显示了创建具有重复元素的列表的两种方法。 nCopies 更有效地创建一个不可变列表,而 Stream.generate 创建一个更灵活的可变列表。
性能比较表明 nCopies 对于大型列表来说更快。 但是,如果您需要可变性或转换,流会提供更多处理选项。
来源
在本文中,我们深入探讨了 Collections.nCopies 方法。 我们涵盖了基本用法、性能特征和替代方案。 此方法对于创建重复元素的节省内存的不可变列表很有价值。
作者
列出所有Java教程。