Java如何将Stream收集到List中
通过不同的方式,我们可以从 Stream 中收集元素并将其存储到 List 中。我们将通过示例比较这几种实现方式,以便我们在不同情形下选择最佳的方法。
在 Java 中,主要有三种方法可以将 Stream 对象收集到 List 对象中。让我们来比较一下这三种方法:
1. 3种方法
1.1 JDK16使用Stream.toList()
- 在 Java 16 中添加了 toList() 方法。这是一个默认方法,它将Stream 元素收集存储到一个不可修改的 List 中。
- 返回的列表是 Collections.unmodifiableList(new ArrayList<>(Arrays.asList(stream.toArray()))) 的实现,其中 stream 表示底层 Stream 的元素。
- 如果Stream是有序的,那么收集好的List中的元素顺序将与Stream流中的顺序保持一致。
- 由于返回的 List 是不可修改的,对任何更改List方法的调用都将引发 UnsupportedOperationException。
- 这是一个终止操作。
Stream<String> tokenStream = Stream.of("A", "B", "C", "D"); List<String> tokenList = tokenStream.toList();
1.2 JDK10使用Stream.collect(Collectors.toUnmodifiableList())
- 在 Java 10 中添加了这个方法。这是一个终止操作,它将 Stream 元素收集到一个不可修改的 List 中。
- 返回的列表是 Collections.unmodifiableList() 的实例,它使用 JDK 内部 API 来填充流项目,这些 API 能够无需使用反射即可访问 JDK 类的私有方法。在这种情况下,不可修改的列表是 SharedSecrets.getJavaUtilCollectionAccess().listFromTrustedArray(list.toArray()) 的实现,其中列表是一个中间的和可变的流元素List。
- 该列表不允许空值,如果流中有空值,整个操作将引发 NullPointerException。
- 如果Stream是有序的,那么收集好的List中的元素顺序将与Stream流中的顺序保持一致。
Stream<String> tokenStream = Stream.of("A", "B", "C", "D"); List<String> tokenList = tokenStream.collect(Collectors.toUnmodifiableList());
1.3. JDK8使用Stream.collect(Collectors.toList())
- 这个方法在Java 8中与原始Stream API一起被添加进来。
- 这是一个终止操作,它把Stream的项收集到一个可变的List中。
- 返回的列表是ArrayList类的一个实例。
- 类似其他JDK版本,如果stream中元素师有序的,那么可变List中的项的顺序将与流中的顺序保持一致。
Stream<String> tokenStream = Stream.of("A", "B", "C", "D"); List<String> tokenList = tokenStream.collect(Collectors.toList());
2. 将流收集到LinkedList中
使用 Collectors.toCollection(LinkedList::new) API 与 Stream.collect() API 一起将流元素收集到LinkedList中。
Stream<String> tokenStream = Arrays.asList("A", "B", "C", "D").stream(); List<String> tokenList = tokenStream .collect(Collectors.toCollection(LinkedList::new));
3.过滤流并收集项目到List
有时,我们需要从流中只找到特定的项,然后将这些项添加到列表中。在这里,我们可以使用 Stream.filter() 方法传递一个Predicate,该谓词将只返回符合给定先决条件的项。
在给定的示例中,我们正在过滤所有工资低于 400 的员工。然后,我们将这些员工收集到一个列表中。
Stream<Employee> employeeStream = Stream.of( new Employee(1, "A", 100), new Employee(2, "B", 200), new Employee(3, "C", 300), new Employee(4, "D", 400), new Employee(5, "E", 500), new Employee(6, "F", 600)); List<Employee> employeeList = employeeStream .filter(e -> e.getSalary() < 400) .collect(Collectors.toList());
4. 从无限流中收集项目到List
要将无限流转换为列表,我们必须将流限制为有限数量的元素(即使用limit()方法进行截断)。给定示例适用于原始数据流的 情况。
IntStream infiniteNumberStream = IntStream.iterate(1, i -> i+1); List<Integer> integerlist = infiniteNumberStream.limit(10) .boxed() .collect(Collectors.toList());
5. 结论
在本教程中,我们学习了与流一起工作的不同方法,并将流项收集到List中。
作为一般准则,我们可以使用 Stream.toList() 用于收集到不可修改的List,并使用 Stream.collect(Collectors.toList()) 用于收集到可修改的List列表。
要收集到任何其他类型的 List 中,我们必须使用l类似 Stream.collect(Collectors.toCollection(LinkedList::new)) 的方法。