当前位置: 首页 > news >正文

Java Stream流详解:从基础语法到实战应用

引言

Java 8 引入的 Stream API 是 Java 编程语言中最具革命性的特性之一。它通过函数式编程的方式,为集合和数组的处理提供了更简洁、更高效的工具。Stream 流的核心思想是“数据处理流水线”,将数据源(如集合、数组)作为输入,通过一系列中间操作(如过滤、映射、排序)和终端操作(如收集、统计)来处理数据,最终生成一个结果。本文将深入解析 Java Stream 流的使用方法、核心特性以及实战案例,帮助开发者更好地掌握这一强大的工具。

一、Stream 的核心特性

1.1 不存储数据

Stream 流本身不存储数据,而是对数据源(如集合、数组)的视图。它更像是对数据源的“加工流水线”,通过一系列操作对数据进行转换和处理,最终输出结果。例如,以下代码展示了如何通过 Stream 对集合进行过滤和映射:

List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
List<String> upperCaseNames = names.stream().filter(name -> name.length() > 3) // 过滤长度大于3的元素.map(String::toUpperCase)          // 转换为大写.collect(Collectors.toList());     // 收集结果

1.2 不可变性

Stream 操作不会修改原始数据源,而是返回一个新的集合或值。例如,filter 操作会筛选符合条件的元素,但原始集合 names 并未被修改。

1.3 延迟执行(惰性求值)

Stream 的中间操作(如 filtermap)是惰性执行的,只有在调用终端操作(如 collectforEach)时,才会真正执行整个流水线操作。这种特性可以优化性能,避免不必要的计算。

1.4 支持串行与并行

Stream 支持串行流(默认)和并行流(通过 parallel() 方法切换)。并行流利用多核 CPU 的优势,可以显著提高大数据量处理的效率。例如:

List<Integer> numbers = IntStream.range(1, 1000000).boxed().collect(Collectors.toList());
int sum = numbers.parallelStream() // 使用并行流.mapToInt(Integer::intValue).sum();

1.5 函数式编程支持

Stream API 基于 Java 8 的函数式编程特性(如 Lambda 表达式、方法引用),使得代码更加简洁和可读。例如,使用 forEach 替代传统的 for 循环:

List<String> list = Arrays.asList("A", "B", "C");
list.forEach(System.out::println);

二、Stream 的创建方式

Stream 可以通过多种方式创建,以下是常见的几种方式:

2.1 从集合创建

Java 8 的 Collection 接口扩展了 stream()parallelStream() 方法,可以直接从集合创建流:

List<String> list = Arrays.asList("a", "b", "c");
Stream<String> stream = list.stream();          // 顺序流
Stream<String> parallelStream = list.parallelStream(); // 并行流

2.2 从数组创建

通过 Arrays.stream() 方法可以将数组转换为流:

int[] array = {1, 2, 3};
IntStream intStream = Arrays.stream(array);

2.3 使用静态方法 of()

Stream.of() 可以直接从一组值创建流:

Stream<String> stringStream = Stream.of("A", "B", "C");
Stream<Integer> integerStream = Stream.of(1, 2, 3);

2.4 无限流(Unbounded Streams)

Stream 提供了 iterategenerate 方法生成无限流,适用于需要动态生成数据的场景:

// 生成斐波那契数列的前10项
Stream.iterate(new int[]{0, 1}, t -> new int[]{t[1], t[0] + t[1]}).limit(10).forEach(t -> System.out.println(t[0]));// 生成随机数
Stream<Double> randomStream = Stream.generate(Math::random).limit(5);

2.5 从文件创建

通过 Files.lines() 方法可以读取文件的每一行作为流:

Path path = Paths.get("data.txt");
Stream<String> lines = Files.lines(path);

三、Stream 的操作类型

Stream 的操作分为 中间操作终端操作 两种类型。中间操作返回新的 Stream,而终端操作触发实际计算并返回结果。

3.1 中间操作(Intermediate Operations)

3.1.1 过滤(Filter)

filter 用于筛选符合条件的元素:

List<String> filtered = list.stream().filter(s -> s.startsWith("A")).collect(Collectors.toList());
3.1.2 映射(Map)

map 将每个元素转换为另一种形式:

List<String> upperCase = list.stream().map(String::toUpperCase).collect(Collectors.toList());
3.1.3 扁平化映射(FlatMap)

flatMap 用于处理嵌套结构(如 List<List<T>>),将其展开为单层流:

List<List<Integer>> nestedList = Arrays.asList(Arrays.asList(1, 2),Arrays.asList(3, 4)
);
List<Integer> flatList = nestedList.stream().flatMap(List::stream).collect(Collectors.toList());
3.1.4 去重(Distinct)

distinct 去除重复元素:

List<Integer> uniqueNumbers = numbers.stream().distinct().collect(Collectors.toList());
3.1.5 排序(Sorted)

sorted 对元素进行排序(自然排序或自定义排序):

List<String> sorted = list.stream().sorted(Comparator.reverseOrder()) // 倒序排序.collect(Collectors.toList());
3.1.6 截取与跳过(Limit/Skip)

limit(n) 截取前 n 个元素,skip(n) 跳过前 n 个元素:

List<Integer> firstFive = numbers.stream().limit(5).collect(Collectors.toList());List<Integer> skipFirstThree = numbers.stream().skip(3).collect(Collectors.toList());

3.2 终端操作(Terminal Operations)

3.2.1 遍历(ForEach)

forEach 用于遍历流中的每个元素:

list.stream().forEach(System.out::println);
3.2.2 收集(Collect)

collect 将流转换为其他数据结构(如 List、Set、Map):

List<String> collectedList = list.stream().collect(Collectors.toList());Set<String> collectedSet = list.stream().collect(Collectors.toSet());Map<String, Integer> collectedMap = list.stream().collect(Collectors.toMap(String::toString,String::length));
3.2.3 聚合操作(Count/Max/Min/Sum/Average)

Stream 提供了多种聚合操作,适用于数值流(如 IntStreamDoubleStream):

long count = numbers.stream().count();
Optional<Integer> max = numbers.stream().max(Integer::compareTo);
Optional<Integer> min = numbers.stream().min(Integer::compareTo);
int sum = numbers.stream().mapToInt(Integer::intValue).sum();
double average = numbers.stream().mapToInt(Integer::intValue).average().orElse(0);
3.2.4 归约(Reduce)

reduce 用于将流中的元素合并为一个值:

Optional<Integer> sum = numbers.stream().reduce((a, b) -> a + b);// 计算乘积
Optional<Integer> product = numbers.stream().reduce((a, b) -> a * b);
3.2.5 匹配(AnyMatch/AllMatch/NoneMatch)

anyMatchallMatchnoneMatch 用于判断流中是否存在满足条件的元素:

boolean hasEven = numbers.stream().anyMatch(n -> n % 2 == 0);boolean allPositive = numbers.stream().allMatch(n -> n > 0);
3.2.6 分组与分区(GroupingBy/PartitioningBy)

Collectors.groupingByCollectors.partitioningBy 用于对流进行分组或分区:

// 按字符串长度分组
Map<Integer, List<String>> groupedByLength = list.stream().collect(Collectors.groupingBy(String::length));// 按是否为偶数分区
Map<Boolean, List<Integer>> partitioned = numbers.stream().collect(Collectors.partitioningBy(n -> n % 2 == 0));

四、Stream 的实战案例

4.1 数据筛选与转换

假设有一个 Person 类,包含姓名、年龄、薪资等属性。我们可以使用 Stream 对数据进行筛选和转换:

class Person {private String name;private int age;private double salary;// 构造方法、getter/setter 省略
}List<Person> people = Arrays.asList(new Person("Alice", 25, 50000),new Person("Bob", 30, 60000),new Person("Charlie", 22, 45000)
);// 筛选年龄大于25岁的人员,并按姓名排序
List<Person> filteredPeople = people.stream().filter(p -> p.getAge() > 25).sorted(Comparator.comparing(Person::getName)).collect(Collectors.toList());

4.2 分组与聚合

使用 Stream 对员工按部门分组,并计算每个部门的平均薪资:

class Employee {private String name;private String department;private double salary;// 构造方法、getter/setter 省略
}List<Employee> employees = Arrays.asList(new Employee("Alice", "HR", 50000),new Employee("Bob", "IT", 60000),new Employee("Charlie", "HR", 45000)
);Map<String, Double> averageSalariesByDepartment = employees.stream().collect(Collectors.groupingBy(Employee::getDepartment,Collectors.averagingDouble(Employee::getSalary)));

4.3 并行流处理大数据

在处理大数据量时,使用并行流可以显著提高性能。例如,计算 1 到 100 万的和:

int sum = IntStream.rangeClosed(1, 1000000).parallel() // 使用并行流.sum();

五、Stream 的最佳实践

5.1 选择合适的流类型

  • 串行流:适用于小数据量或单线程任务。
  • 并行流:适用于大数据量且需要高性能的场景,但需注意线程安全问题。

5.2 避免在中间操作中使用副作用

中间操作(如 forEach)不应修改外部状态,因为流的执行顺序可能因并行化而变化。

5.3 合理使用 Optional

终端操作(如 findFirstmax)返回 Optional,应使用 orElseifPresent 等方法处理可能的空值:

Optional<Integer> max = numbers.stream().max(Integer::compareTo);
int result = max.orElse(0); // 如果流为空,返回默认值0

5.4 避免在流中进行复杂的业务逻辑

流更适合用于简单的数据处理,复杂的业务逻辑应拆分为独立的方法或类。

六、总结

Java Stream 流通过函数式编程的方式,极大地简化了集合和数组的处理。其核心特性包括惰性执行不可变性函数式编程支持,使得代码更加简洁、可读性更高。通过掌握 Stream 的创建方式、中间操作和终端操作,开发者可以高效地处理数据,甚至在大数据量场景下利用并行流提升性能。

在实际开发中,合理使用 Stream 可以减少冗余代码,提高开发效率。然而,也需注意避免滥用并行流、在中间操作中引入副作用等问题。通过结合具体业务场景,Stream 流将成为 Java 开发者不可或缺的工具。

附录:常用 Stream 操作速查表

操作类型方法功能
中间操作filter(Predicate)过滤符合条件的元素
map(Function)转换每个元素
flatMap(Function)扁平化处理嵌套结构
distinct()去重
sorted(Comparator)排序
limit(n)截取前 n 个元素
skip(n)跳过前 n 个元素
终端操作forEach(Consumer)遍历每个元素
collect(Collector)收集结果(转为 List、Set、Map 等)
count()返回元素个数
max(Comparator)返回最大值
min(Comparator)返回最小值
reduce(BinaryOperator)归约操作
anyMatch(Predicate)是否存在符合条件的元素
allMatch(Predicate)是否所有元素都符合条件
noneMatch(Predicate)是否没有元素符合条件
findFirst()返回第一个元素
findAny()返回任意元素(适用于并行流)

通过以上内容,相信读者已经对 Java Stream 流有了全面的了解。无论是处理小规模数据还是大规模数据,Stream API 都能提供优雅且高效的解决方案。希望本文能帮助开发者在实际项目中更好地应用 Stream 流,提升代码质量和开发效率。

http://www.xdnf.cn/news/1273141.html

相关文章:

  • spring-ai整合PGVector实现RAG
  • 【代码随想录day 15】 力扣 257. 二叉树的所有路径
  • uni-app 网络请求终极选型:uni.request、axios、uni-network、alova 谁才是你的真命请求库?
  • LeetCode_字符串
  • LeetCode 刷题【37. 解数独】
  • 计算XGBoost分类模型的错误率
  • 网工笔记——BGP协议
  • 解决 Linux 下 “E: 仓库xxx没有数字签名” 问题
  • 编程基础之多维数组——同行列对角线的格
  • scanpy单细胞转录组python教程(四):单样本数据分析之降维聚类及细胞注释
  • (Python)爬虫进阶(Python爬虫教程)(CSS选择器)
  • stm32没有CMSIS文件
  • 【精彩回顾·成都】成都 User Group×柴火创客空间:开源硬件驱动 AI 与云的创新实践!
  • vue和react和uniapp的状态管理分别是什么,并且介绍和怎么使用
  • Day38--动态规划--322. 零钱兑换,279. 完全平方数,139. 单词拆分,56. 携带矿石资源(卡码网),背包问题总结
  • 如何理解SA_RESTART”被信号中断的系统调用自动重启“?
  • Vue3 组件化开发
  • 人工智能技术发展历史演变
  • Filter,Interceptor拦截器-登录校验
  • 关于城市农村创业的一点构想
  • RecyclerView 缓存机制
  • 堆----3.数据流的中位数
  • Slab 算法浅析
  • HTML全景效果实现
  • 【Python 语法糖小火锅 · 第 2 涮】
  • 容器技术基础与实践:从镜像管理到自动运行配置全攻略
  • 【数据分享】各省农业土地流转率(2010-2023)
  • 【Python 语法糖小火锅 · 第 4 涮】
  • 【Python 语法糖小火锅 · 第 3 涮】
  • 【unitrix数间混合计算】2.9 小数部分特征(t_non_zero_bin_frac.rs)