Java8 Stream 简单使用

news/2025/2/11 16:22:07/文章来源:https://www.cnblogs.com/wkfvawl/p/18709994

参考

https://medium.com/javarevisited/you-dont-know-java-streams-in-practice-do-you-826e6aebba81
https://www.baeldung.com/java-8-streams
https://stackify.com/streams-guide-java-8/
《Java8 实战》

创建流

最常用的方法是直接使用 Collection 接口上的 stream 方法从一个容器中创建流:

List<Employee> employees = Arrays.asList(new Employee());
Stream<Employee> stream = employees.stream();
Stream<String> stream = Stream.of("Mary", "Tom", "", "Allen");

如果是数组的话,可以使用 Arrays.stream 方法:

int[] numbers = {2, 3, 5, 7, 11, 13}; 
IntStream sum = Arrays.stream(numbers).

使用 Stream 的 builder 方法创建流:

Stream.Builder<Employee> empStreamBuilder = Stream.builder();empStreamBuilder.accept(arrayOfEmps[0]);
empStreamBuilder.accept(arrayOfEmps[1]);
empStreamBuilder.accept(arrayOfEmps[2]);Stream<Employee> empStream = empStreamBuilder.build();

中间操作(intermediate operation)

连接起来的操作称之为中间操作,就像自来水管,一节一节连接起来。中间操作接收一个流并返回另一个流。

先创建一个员工流

public List<Employee> employees = Arrays.asList(new Employee(1, "Tom", 4_000, "2001-02-13"),new Employee(2, "Jack", 2_000, "2001-02-13"),new Employee(3, "Jack", 2_000, "2001-02-13"),new Employee(4, "Jack 1", 2_000, "2024-02-13"),new Employee(5, "练习时长2年半", 2_000, "2011-02-13"),new Employee(6, "练习时长2年半", 2_000, "2001-02-13"),null
);

filter

过滤符合条件的元素。

// 过滤出 id 为 1 的员工
List<Employee> collect = employees.stream().filter(e -> e.getId() == 1).collect(Collectors.toList());

map

将元素映射成另一个元素。

List<String> collect = employees.stream().map(Employee::getName).collect(Collectors.toList());

flatMap

拍扁,接受一个将元素转为 Stream 的函数式接口,返回一个将所有元素转换成的流聚合之后的流。

List<String> words = Arrays.asList("aaa", "a", "bc");
List<String> uniqueCharacters = words.stream().map(w -> w.split("")).flatMap(Arrays::stream).distinct().collect(Collectors.toList());

distinct

对流中的元素去重,使用流中的对象的 equals 方法来判断两个元素是否重复,所以记得按照自己的需要重写 equals 方法和 hashcode 方法。

List<Employee> collect = employees.stream().distinct().collect(Collectors.toList());

limit

和 SQL 中的 limit 关键字一样,limit 会返回一个不超过给定长度的流(限制只保留指定个数的元素)。

// 取流中第一个工资等于 1000 的员工
List<Employee> collect = employees.stream().filter(e -> Objects.nonNull(e) && e.getSalary() == 1_000).limit(1).collect(Collectors.toList());

skip

跳过流中指定个数的元素。

// 先过滤出工资等于 1000 的员工,再跳过前两个员工(从第 3 个员工开始取)
List<Employee> collect = employees.stream().filter(e -> Objects.nonNull(e) && e.getSalary() == 1_000).skip(2).collect(Collectors.toList());

sorted

按照指定的比较器排序流中的元素(如果不传比较器,那么流中的对象需要实现 Comparable 接口)。

// 按照员工的薪资排序
List<Employee> collect = employees.stream().sorted(Comparator.comparing(Employee::getSalary)).collect(Collectors.toList());

查找和匹配

allMatch、anyMatch、noneMatch、findFirst、findAny

findAny 不是为了随机选中,而是为了最快的选择出元素,如果 findAny 选择了 Null,会抛出空指针异常

boolean anyMatch = employees.stream().anyMatch(e -> e.getSalary() == 1_000);
boolean noEmpIsNull = employees.stream().allMatch(Objects::nonNull);
boolean haveNoOneEmpNameIsTomCat = employees.stream().noneMatch(e -> "TomCat".equals(e.getName()));
Optional<Employee> firstEmp = employees.stream().findFirst();
Optional<Employee> anyEmp = employees.parallelStream().findAny();

终端操作(terminate operation)

终端操作就像是水龙头,它的后面不会再有任何的中间操作,终端操作是生成结果的步骤。

collect

将流中的元素收集起来,接收一个 Collector 接口的实现,最常用的就是传入一个将流中的元素采集到一个 List 中的采集器(上面的例子都在使用)。

groupingBy

将流中的元素按照指定的值作为分组依据将流中的元素分组。

// 将员工按照部门进行分组
Map<String, List<Employee>> groupByEmp = employees.stream().collect(Collectors.groupingBy(Employee::getDept));

reducing

将流中的元素合并为一个结果元素。

// 求所有员工的工资总和
Integer sumSalary = employees.stream().collect(Collectors.reducing(0, Employee::getSalary, Integer::sum));

joining

将流中的元素通过指定的分隔符拼接起来。

String allEmpName = employees.stream().map(Employee::getName).collect(Collectors.joining(", "));

summingInt 和 avging

summingInt 是求和,avging 是求平均值。

Integer sumSalary = employees.stream().collect(Collectors.summingInt(Employee::getSalary));

maxBy 和 minBy

maxBy 是求最大值,minBy 是求最小值。

Comparator<Employee> empCaloriesComparator = Comparator.comparingInt(Employee::getSalary);
Optional<Employee> salaryMostHighEmp = employees.stream().collect(Collectors.maxBy(empCaloriesComparator));
Optional<Employee> salaryMostLowEmp = employees.stream().collect(Collectors.minBy(empCaloriesComparator));

forEach

对流中的每一个元素执行指定的操作。

// 打印每一个员工
employees.stream().forEach(e -> {System.out.println(e.toString());
});

reduce

按照指定的规则将流中的元素合并为一个元素。

// 求所有员工薪水之和
Integer sumSalary = employees.stream().map(Employee::getSalary).reduce(0, Integer::sum);

count

和 SQL 中的 count 一样,统计流中的元素的个数。

// 统计员工数量
long empNm = employees.stream().filter(Objects::nonNull).count();

sum

和 SQL 中的 sum 一样,求流中的元素的和(需要先将流转化为数值类型的流)。

// 求流中所有元素的和
Integer sumSalary = employees.stream().mapToInt(Employee::getSalary).sum();

并行流

并行处理流中的数据。

employees.stream().parallel().forEach(e -> e.salaryIncrement(10.0));
Stream<Product> streamOfCollection = employees.parallelStream();

注意点

  1. 流只能消费一次
List<String> title = Arrays.asList("Java8", "In", "Action"); 
Stream<String> s = title.stream(); 
s.forEach(System.out::println); 
// java.lang.IllegalStateException:流已被操作或关闭
s.forEach(System.out::println);
  1. 流的中间操作是懒加载的

只有执行了终端操作才能触发处理,而且下一步不是需要等到上一步所有的数据都处理完了才开始执行当前步骤,整个处理过程是"流"的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/882132.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络流 笔记

本文原在 2024-07-22 10:17 发布于本人洛谷博客。 一、定义与性质 1. 基本定义 从水厂出发,有很多节点和水管,节点不能存水,但容量无限,水管有容量上限,全部水管最终经过某些节点都会流向某个工厂里,问最多同时能给工厂发多少水? 流网络:这张图。 源点:水厂。 汇点:工…

CentOS7 - firewalld只允许国内ip访问

firewalld只允许国内ip访问 #查看public区域大致情况 firewall-cmd --zone=public --list-all #获取china ip源 wget --no-check-certificate -O- http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest | awk -F\| /CN\|ipv4/ { printf("%s/%d\n", $4, 32…

2025 寒假集训 第二期

2025 寒假集训 第二期 J - Shift and Flip 题意:给出两个 \(01\) 串 \(A,B\) ,要求使两串相等,可以执行以下三种操作将 \(A\) 左移一个单位 将 \(A\) 右移一个单位 选择一个位置 \(i\) 满足 \(B_i=1\) ,使 \(A_i\) 取反求最小操作数。 思路:不可能的情况只有当 \(B\) 全为…

为word中的图片批量添加边框

写报告时,经常会在word中插入几十张甚至是上百张图片,而为了美观,通常会为这些图片添加边框,但一个个添加显然是疯狂且愚蠢的,我们应该做一些更有效率的事情。 使用python-docx来实现我们的操作(由于各种原因,不会选择用宏) 首先观察一下图片加边框前后的文档结构变化(…

DeepSeek本地化部署超简单!快给你的大模型安排上聊天助手吧!

上一篇我们讲了如何把deepseek R1 安装部署到个人电脑上。(感兴趣的请跳转至 https://www.cnblogs.com/AI2025/p/18709288) 但是,我们部署完了发现,如果仅仅是只在黑漆漆的命令行里面去和AI对话聊天,感觉很不人性化,也不好用。那么,有没有更好的和AI交互聊天的工具呢? …

prometheus监控k8s并发送报警

1.编辑prometheus的configmap文件kubectl edit cm prometheus-1738826520-server2.添加如下红色字体apiVersion: v1 data:alerting_rules.yml: |-groups:- name: deployment Monitoringrules:- alert: DeploymentReplicasUnavailableexpr: kube_deployment_status_replicas_una…

VS2022 安装失败 : 未能安装包“Microsoft.VisualStudio.JavaScript.SDK_1.0.1738743,version=1.0.1738743”

VS2022 安装失败,异常提醒: 1、未能安装包“Microsoft.VisualStudio.JavaScript.SDK_1.0.1738743,version=1.0.1738743” 2、未能安装包“Microsoft.Windows.SDK.BuildTools_10.0.26100.1742,version=1.0.0.0” 问题原因,可以直接查看本地安装异常日志文件,文件中的描述应该…

项目管理证书报考条件:不同证书的对比分析

项目管理领域的证书众多,它们在行业内都具有一定的认可度和价值。对于有意投身项目管理行业或提升自身项目管理能力的人来说,了解不同证书的报考条件至关重要。这不仅关系到能否顺利报考,更影响着未来的职业发展方向。接下来,我们将对几种常见的项目管理证书报考条件进行对…

C# 迷宫求解算法,给出思路和例子。

C# 迷宫求解算法 迷宫求解通常可以使用 深度优先搜索(DFS)、广度优先搜索(BFS)、A(A-star)搜索* 或 Dijkstra 算法。以下是几种常见方法的思路及代码示例。1. 迷宫表示 迷宫通常可以使用 二维数组(char[,] 或 int[,])来表示:0 表示可以通过的路径 1 表示墙或障碍物 S(…

No.18 Kappa系数精度评价2.0

# Loading necessary libraries library(openxlsx) library(vcd)# Reading the Excel data AccData <- read.xlsx("D:/R_proj/a绘图demo/bKappa/五指山生态系统分类精度评价一二级类.xlsx",sheet = 1, colNames = T)# Handle missing values (replace NA with 0) …

什么是回溯法,给个C#简单的例子。

回溯法(Backtracking)是一种搜索算法,主要用于解决组合优化问题,如全排列、子集、数独、八皇后问题等。它通过递归的方式尝试所有可能的解决方案,并在发现当前路径无法得到正确答案时回溯到上一步,继续尝试其他路径。 回溯法的基本思想选择:选择一个可能的选项。 约束:…

如何挑选项目型企业管理系统?10款软件为你解答

本文介绍了以下10款项目型企业管理系统:1.Worktile;2.PingCode;3.Teambition;4.石墨文档;5.蓝鲸智云;6.Trello;7.Asana;8.Monday.com;9.Jira;10.Basecamp。在日益复杂的项目管理环境中,很多企业面临一个共同的挑战:如何高效、精准地管理多个项目、协调各方资源,并…