1. 概述

本文将介绍如何在Java中打乱集合元素的顺序。Java内置了针对List对象的打乱方法——我们将利用它处理其他类型的集合。

2. 打乱List

**核心方法是java.util.Collections.shuffle**,它接收一个List作为输入并原地打乱顺序(in-place)。所谓"原地",指直接修改传入的列表,而非创建新列表。

看个简单示例:

List<String> students = Arrays.asList("Foo", "Bar", "Baz", "Qux");
Collections.shuffle(students);

java.util.Collections.shuffle还有重载版本,支持自定义随机数源。当需要确定性打乱结果时(比如测试场景),这个特性特别有用。

下面演示用相同随机源打乱两个列表:

List<String> students_1 = Arrays.asList("Foo", "Bar", "Baz", "Qux");
List<String> students_2 = Arrays.asList("Foo", "Bar", "Baz", "Qux");

int seedValue = 10;

Collections.shuffle(students_1, new Random(seedValue));
Collections.shuffle(students_2, new Random(seedValue));

assertThat(students_1).isEqualTo(students_2);

⚠️ 关键点:当使用相同种子初始化的随机源时,两次打乱产生的随机数序列完全一致,最终列表顺序也必然相同。

3. 打乱无序集合的元素

我们可能需要打乱SetMap这类集合,但它们本质上都是无序的——不维护特定顺序。

虽然某些实现(如LinkedHashMap或带ComparatorSet)会维护固定顺序,但同样不能直接打乱。

变通方案:先将集合转为List,再打乱这个List

Map为例:

Map<Integer, String> studentsById = new HashMap<>();
studentsById.put(1, "Foo");
studentsById.put(2, "Bar");
studentsById.put(3, "Baz");
studentsById.put(4, "Qux");

List<Map.Entry<Integer, String>> shuffledStudentEntries
 = new ArrayList<>(studentsById.entrySet());
Collections.shuffle(shuffledStudentEntries);

List<String> shuffledStudents = shuffledStudentEntries.stream()
  .map(Map.Entry::getValue)
  .collect(Collectors.toList());

类似地处理Set

Set<String> students = new HashSet<>(
  Arrays.asList("Foo", "Bar", "Baz", "Qux"));
List<String> studentList = new ArrayList<>(students);
Collections.shuffle(studentList);

4. 使用Java 8 Streams API打乱列表

通过Java Streams API打乱列表时,可将打乱操作集成到流处理管道中。核心思路:

  1. stream()将列表转为流
  2. 通过Collectors.toList()收集为新列表
  3. Collections.shuffle()打乱这个新列表

关键技巧:使用Collectors.collectingAndThen()在收集后执行打乱操作,保持代码简洁:

public static List<String> shuffleList(List<String> list) {
    return list.stream()
      .collect(Collectors.collectingAndThen(Collectors.toList(), collected -> {
          Collections.shuffle(collected);
          return collected;
      }));
}

注:虽然标题提到"整数列表",但示例使用的是String列表——方法同样适用于任何类型的列表。

5. 总结

本文展示了使用java.util.Collections.shuffle打乱各类Java集合的方法:

  • 直接用于List对象
  • 间接用于其他集合(先转为List
  • 通过自定义随机源控制打乱结果(如实现确定性打乱)

所有示例代码可在GitHub获取。


原始标题:Shuffling Collections in Java | Baeldung