在Java中,Stream API 是 Java 8 引入的一个重要特性,它提供了一种高效且声明式的处理数据集合的方式。使用 Stream API,你可以对集合进行复杂的查询和数据转换操作,而不必明确编写复杂的循环语句。Stream 操作是高度优化的,并且可以透明地支持并行处理。
Stream 基础
Stream 是对集合的包装,通常由获取源(如集合、数组)生成。Stream 操作可以序列化执行或并行执行。
创建 Stream
Stream 可以通过多种方式创建。以下是一些常见的示例:
import java.util.*;
import java.util.stream.*;
public class StreamExamples {
public static void main(String[] args) {
// 从集合创建 Stream
List<String> list = Arrays.asList("Apple", "Banana", "Cherry");
Stream<String> stream = list.stream();
// 从数组创建 Stream
Integer[] numbers = {1, 2, 3, 4, 5};
Stream<Integer> numberStream = Arrays.stream(numbers);
// 使用 Stream.of()
Stream<String> streamOf = Stream.of("A", "B", "C");
// 创建无限 Stream
Stream<Integer> infiniteStream = Stream.iterate(0, n -> n + 1);
}
}
常用操作
Stream 操作分为中间操作和终端操作。
- 中间操作:如
filter
,map
,sorted
等,它们返回一个新的 Stream,可以链式调用。 - 终端操作:如
forEach
,collect
,reduce
等,它们输出结果或产生副作用,并关闭 Stream。
示例:使用 Stream
下面是一些使用 Stream 进行数据处理的示例:
import java.util.*;
import java.util.stream.*;
public class StreamExamples {
public static void main(String[] args) {
List<String> names = Arrays.asList("John", "Jane", "Adam", "Diana");
// Example 1: 筛选和打印
names.stream()
.filter(name -> name.startsWith("J"))
.forEach(System.out::println); // 输出 John, Jane
// Example 2: 转换和收集
List<String> upperNames = names.stream()
.map(String::toUpperCase)
.collect(Collectors.toList());
System.out.println(upperNames); // 输出 [JOHN, JANE, ADAM, DIANA]
// Example 3: 排序、筛选和归约
Optional<String> longestName = names.stream()
.sorted(Comparator.comparingInt(String::length).reversed())
.findFirst();
longestName.ifPresent(System.out::println); // 输出 Diana
// Example 4: 聚合操作
int totalLength = names.stream()
.mapToInt(String::length)
.sum();
System.out.println("Total length: " + totalLength); // 输出总字符数
}
}
并行 Streams
Stream API 支持并行操作,可以通过 parallelStream()
或 parallel()
方法启用。并行 Stream 利用多核架构自动并行化操作。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6);
int sum = numbers.parallelStream()
.mapToInt(Integer::intValue)
.sum();
System.out.println("Sum: " + sum);
注意事项
- Stream 一旦经过终端操作,就会被消耗掉,不能再被使用。
- Stream 操作不修改源数据,而是返回一个持有结果的新 Stream 或其他值。
- 并行 Stream 应谨慎使用,因为并行化处理不一定适用于所有情况,可能会引起线程安全问题或性能下降。
我们可以开始利用 Java 的 Stream API 来简化集合处理的代码,使其更加清晰和高效。