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教程。