Stream 是 Java 8 引入的一个强大的数据处理抽象,它允许你以声明式方式处理数据集合(类似于 SQL 语句),支持并行操作,提高了代码的可读性和处理效率。
不是数据结构:不存储数据,只是从数据源(集合、数组等)获取数据
函数式风格:支持 lambda 表达式和方法引用
延迟执行:许多操作(中间操作)不会立即执行,只有遇到终止操作才会执行
可消费性:Stream 只能被消费一次,用完即失效
中间操作(Intermediate Operations):返回 Stream 本身,可以链式调用(如 filter, map)
终止操作(Terminal Operations):产生最终结果或副作用(如 forEach, collect)
// 1. 从集合创建
List list = Arrays.asList("a", "b", "c");
Stream stream1 = list.stream(); // 顺序流
Stream parallelStream = list.parallelStream(); // 并行流
// 2. 从数组创建
String[] array = {"a", "b", "c"};
Stream stream2 = Arrays.stream(array);
// 3. 使用Stream.of()
Stream stream3 = Stream.of("a", "b", "c");
// 4. 使用Stream.generate() 无限流
Stream randomStream = Stream.generate(Math::random).limit(5);
// 5. 使用Stream.iterate() 迭代流
Stream iterateStream = Stream.iterate(0, n -> n + 2).limit(10);
// filter(Predicate) 过滤符合条件的元素
List filtered = list.stream()
.filter(s -> s.startsWith("a"))
.collect(Collectors.toList());
// map(Function) 将元素转换为其他形式
List lengths = list.stream()
.map(String::length)
.collect(Collectors.toList());
// flatMap 将多个流合并为一个流
List flatMapped = list.stream()
.flatMap(s -> Stream.of(s.split("")))
.collect(Collectors.toList());
// distinct() 去重
List distinct = list.stream().distinct().collect(Collectors.toList());
// sorted() 自然排序
List sorted = list.stream().sorted().collect(Collectors.toList());
// sorted(Comparator) 自定义排序
List customSorted = list.stream()
.sorted((s1, s2) -> s2.compareTo(s1))
.collect(Collectors.toList());
// limit(long) 限制元素数量
// skip(long) 跳过前N个元素
// peek(Consumer) 查看流中元素(主要用于调试)
// forEach(Consumer) 遍历每个元素
list.stream().forEach(System.out::println);
// collect(Collector) 将流转换为集合或其他形式
List collectedList = stream.collect(Collectors.toList());
Set collectedSet = stream.collect(Collectors.toSet());
Map map = stream.collect(
Collectors.toMap(Function.identity(), String::length));
// count() 计数
long count = list.stream().count();
// max/min(Comparator) 最大/最小值
Optional max = list.stream().max(Comparator.naturalOrder());
// reduce 归约操作
Optional sum = Stream.of(1, 2, 3).reduce(Integer::sum);
// anyMatch 任意元素匹配
boolean anyStartsWithA = list.stream().anyMatch(s -> s.startsWith("a"));
// allMatch 所有元素匹配
boolean allStartsWithA = list.stream().allMatch(s -> s.startsWith("a"));
// noneMatch 没有元素匹配
boolean noneStartsWithZ = list.stream().noneMatch(s -> s.startsWith("z"));
Java 8 提供了专门的数值流,避免装箱拆箱开销:
// IntStream, LongStream, DoubleStream
IntStream intStream = IntStream.range(1, 100); // 1-99
DoubleStream doubleStream = DoubleStream.of(1.1, 2.2);
// 常用数值操作
int sum = IntStream.rangeClosed(1, 100).sum(); // 1-100的和
OptionalDouble avg = IntStream.of(1, 2, 3).average();
// 创建并行流
List parallelProcessed = list.parallelStream()
.filter(s -> s.length() > 1)
.collect(Collectors.toList());
// 注意事项:
// 1. 确保操作是线程安全的
// 2. 避免有状态的操作
// 3. 数据量足够大时才使用并行流
// 分组
Map> groupByLength = list.stream()
.collect(Collectors.groupingBy(String::length));
// 分区
Map> partition = list.stream()
.collect(Collectors.partitioningBy(s -> s.startsWith("a")));
// 连接字符串
String joined = list.stream().collect(Collectors.joining(", "));
// 汇总统计
IntSummaryStatistics stats = list.stream()
.collect(Collectors.summarizingInt(String::length));
List people = ...;
// 获取所有成年人的姓名列表
List adultNames = people.stream()
.filter(p -> p.getAge() >= 18)
.map(Person::getName)
.collect(Collectors.toList());
// 按城市分组
Map> byCity = people.stream()
.collect(Collectors.groupingBy(Person::getCity));
// 计算每个城市的平均年龄
Map avgAgeByCity = people.stream()
.collect(Collectors.groupingBy(
Person::getCity,
Collectors.averagingInt(Person::getAge)
));
// 读取文件并处理
try (Stream lines = Files.lines(Paths.get("data.txt"))) {
long wordCount = lines
.flatMap(line -> Arrays.stream(line.split("\\s+")))
.filter(word -> word.length() > 0)
.count();
} catch (IOException e) {
e.printStackTrace();
}
流只能消费一次:尝试第二次使用已关闭的流会抛出 IllegalStateException
避免修改源数据:流操作期间不应修改源集合
合理使用并行流:并非所有情况都适合并行,小数据量可能适得其反
注意自动装箱:数值操作尽量使用原始类型特化流(IntStream等)
延迟执行特性:没有终止操作,中间操作不会执行
Stream API 提供了一种高效、声明式的数据处理方式,是现代 Java 编程中不可或缺的工具。合理使用可以大幅提升代码的可读性和维护性。