Java的Stream流使用指南

news/2023/6/7 23:54:57

准备数据:

List<User> userList = new ArrayList<>(16);
User user = new User();
user.setUserId(IdWorker.getId()).setUsername("欧阳正才").setRole("1admin").setAge(18).setMoney(new BigDecimal("9915.80")).setAddress("山东济南");
User user1 = new User();
user1.setUserId(IdWorker.getId()).setUsername("刘露").setRole("super-admin").setAge(19).setMoney(new BigDecimal("1580")).setAddress("山东济南");
User user2 = new User();
user2.setUserId(IdWorker.getId()).setUsername("李彦宏").setRole("1admin").setAge(35).setMoney(new BigDecimal("560")).setAddress("山东济南");
User user3 = new User();
user3.setUserId(null).setUsername("崔福来").setRole("user").setAge(21).setMoney(new BigDecimal("0.0")).setAddress("山东济南");
User user4 = new User();
user4.setUserId(IdWorker.getId()).setUsername("欧阳正才").setRole("admin").setAge(28).setMoney(new BigDecimal("9915.80")).setAddress("山东济南");
userList.add(user);
userList.add(user1);
userList.add(user2);
userList.add(user3);
userList.add(user4);数据如下:
[{"address":"山东济南","age":18,"money":9915.80,"role":"1admin","userId":1507225552322748417,"username":"欧阳正才"},{"address":"山东济南","age":19,"money":1580,"role":"super-admin","userId":1507225552322748418,"username":"刘露"},{"address":"山东济南","age":35,"money":560,"role":"1admin","userId":1507225552322748419,"username":"李彦宏"},{"address":"山东济南","age":21,"money":0.0,"role":"user","username":"崔福来"},{"address":"山东济南","age":28,"money":9915.80,"role":"admin","userId":1507225552322748420,"username":"欧阳正才"}
]

filter

使用 filter() 过滤列表数据

// 获取年龄大于20的用户列表
List<User> users = userList.stream().filter(i -> i.getAge() > 20).collect(Collectors.toList());
log.info(JSONObject.toJSONString(users));结果:
[{"address":"山东济南","age":35,"money":560,"role":"1admin","userId":1507224853342052355,"username":"李彦宏"},
{"address":"山东济南","age":21,"money":0.0,"role":"user","username":"崔福来"},
{"address":"山东济南","age":28,"money":9915.80,"role":"admin","userId":1507224853342052356,"username":"欧阳正才"}]

findAny、findFirst

注意:findFirst() 和 findAny() 都是获取列表中的第一条数据,但是findAny()操作,返回的元素是不确定的,对于同一个列表多次调用findAny()有可能会返回不同的值。使用findAny()是为了更高效的性能。如果是数据较少,串行地情况下,一般会返回第一个结果,如果是并行(parallelStream并行流)的情况,那就不能确保是第一个。

// 获取权限是admin而且用户名带‘李’的用户,任何一个,没有则返回null
User user = userList.stream().filter(i -> "admin".equals(i.getRole()) && isNotBlank(i.getUsername()) && i.getUsername().contains("李")).findAny().orElse(null);

anyMatch、allMatch、noneMatch

anyMatch判断数据列表中是否存在任意一个元素符合设置的predicate条件,如果是就返回true,否则返回false。allMatch判断数据列表中全部元素都符合设置的predicate条件,如果是就返回true,否则返回false,流为空时总是返回true。noneMatch判断数据列表中全部元素都不符合设置的predicate条件,如果是就返回true,否则返回false,流为空时总是返回true。

// 是否有工资 > 10000的数据,有1个就是true
boolean money = userList.stream().anyMatch(i -> (null != i.getMoney() ? i.getMoney() : BigDecimal.ZERO).compareTo(new BigDecimal("10000")) > 0);
// 是否全部员工工资 >= 100
boolean money1 = userList.stream().allMatch(i -> (null != i.getMoney() ? i.getMoney() : BigDecimal.ZERO).compareTo(new BigDecimal("100")) >= 0);
// 是否工资都不大于10000
boolean money2 = userList.stream().noneMatch(i -> (null != i.getMoney() ? i.getMoney() : BigDecimal.ZERO).compareTo(new BigDecimal("10000")) > 0);

reduce((T, T) - T) 和 reduce(T, (T, T) - T)

用于组合流中的元素,如求和,求积,求最大值等

// 用户列表中年龄的最大值、最小值、总和
int maxAge = userList.stream().map(User::getAge).reduce(Integer::max).get(); // 35
int minAge = userList.stream().map(User::getAge).reduce(Integer::min).get(); // 18
int allAge = userList.stream().map(User::getAge).reduce(0, Integer::sum); // 121

计算元素总和的方法其中暗含了装箱成本,map(User::getAge) 方法过后流变成了 Stream类型,而每个 Integer 都要拆箱成一个原始类型再进行 sum 方法求和,这样大大影响了效率。针对这个问题 Java 8 有良心地引入了数值流 IntStream, DoubleStream, LongStream,这种流中的元素都是原始数据类型,分别是 int,double,long。

// 使用mapToInt() 求用户列表中年龄的最大值、最小值、总和、平均值。
int maxVal = userList.stream().mapToInt(User::getAge).max().getAsInt(); // 35
int minVal = userList.stream().mapToInt(User::getAge).min().getAsInt(); // 18
int sumVal = userList.stream().mapToInt(User::getAge).sum(); // 121
double aveVal = userList.stream().mapToInt(User::getAge).average().getAsDouble(); // 24.2
// 统计角色是admin的人数,使用 counting()方法进行统计
long userCount = userList.stream().filter(i -> "admin".equals(i.getRole())).collect(Collectors.counting());
// 统计角色是admin的人数,使用 counting()方法进行统计(推荐)
long userCount1 = userList.stream().filter(i -> "admin".equals(i.getRole())).count();

summingInt()、summingLong()、summingDouble():用于计算总和,需要一个函数参数。

// 计算年龄总和
int sumAge = userList.stream().collect(Collectors.summingInt(User::getAge)); // 121

averagingInt()、averagingLong()、averagingDouble():用于计算平均值。

// 计算平均年龄
double aveAge = userList.stream().collect(Collectors.averagingDouble(User::getAge));

summarizingInt()、summarizingLong()、summarizingDouble()

这三个方法比较特殊,比如 summarizingInt 会返回 IntSummaryStatistics 类型。IntSummaryStatistics类提供了用于计算的平均值、总数、最大值、最小值、总和等方法。

// 获取IntSummaryStatistics对象
IntSummaryStatistics ageStatistics = userList.stream().collect(Collectors.summarizingInt(User::getAge));// 统计:最大值、最小值、总和、平均值、总数
System.out.println("最大年龄:" + ageStatistics.getMax()); // 35
System.out.println("最小年龄:" + ageStatistics.getMin()); // 18
System.out.println("年龄总和:" + ageStatistics.getSum()); // 121
System.out.println("平均年龄:" + ageStatistics.getAverage()); // 24.2
System.out.println("员工总数:" + ageStatistics.getCount()); // 5

针对BigDecimal类型

// 最高薪资
BigDecimal maxMoney = userList.stream().map(User::getMoney).max(BigDecimal::compareTo).get();
// 最低薪资
BigDecimal minMoney = userList.stream().map(User::getMoney).min(BigDecimal::compareTo).get();
// 薪资总和
BigDecimal sumMoney = userList.stream().map(User::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add);
//平均薪资
BigDecimal avgMoney = userList.stream().map(User::getMoney).reduce(BigDecimal.ZERO, BigDecimal::add).divide(BigDecimal.valueOf(userList.size()), 2, BigDecimal.ROUND_HALF_UP);
System.out.println("最高薪资:" + maxMoney + "元"); // 9915.80元
System.out.println("最低薪资:" + minMoney + "元"); // 0.0元
System.out.println("薪资总和:" + sumMoney + "元"); // 21971.60元
System.out.println("平均薪资:" + avgMoney + "元"); // 4394.32元

sorted() / sorted((T, T) - int)

排序方法。如果流中的元素的类实现了 Comparable 接口,即有自己的排序规则,那么可以直接调用 sorted() 方法对元素进行排序,如 Stream。反之, 需要调用sorted((T, T) - int)实现 Comparator 接口。

// 根据年龄排序(升序)
userList = userList.stream().sorted(Comparator.comparingInt(User::getAge)).collect(Collectors.toList());
// 根据年龄排序(降序)
userList = userList.stream().sorted(Comparator.comparingInt(User::getAge).reversed()).collect(Collectors.toList());

groupingBy

可以接受一个第二参数实现多级分组

// 获取大于18岁的,并根据角色role分组Map,key=role
Map<String, List<User>> userGroupbyRoleMap = userList.stream().filter(i -> i.getAge() > 18).collect(Collectors.groupingBy(User::getRole));// 根据角色和金额对用户列表进行分组
Map<String, Map<BigDecimal, List<User>>> userMap = userList.stream().collect(Collectors.groupingBy(User::getRole, Collectors.groupingBy(User::getMoney)));// 根据角色和金额对用户列表进行分组(map的key,如果userId有null则替换为-1)
Map<String, Map<BigDecimal, List<User>>> userMap1 = userList.stream().collect(Collectors.groupingBy(User::getRole, Collectors.groupingBy(i -> i.getUserId() == null ? -1 : i.getUserId())));
// 根据角色进行分组,汇总各个角色用户的平均年龄
Map<String, Double> userRoleMap = userList.stream().collect(Collectors.groupingBy(User::getRole, Collectors.averagingInt(User::getAge)));
System.out.println(JSONObject.toJSONString(userRoleMap));{"super-admin":19.0,"admin":27.0,"user":21.0}// 将导入的数据根据台账号分组,如果accountNo是null,则先将accountNo替换为空串""
Map<String, List<ImportAccountGeneralEntity>> accountGeneralEntityMap = accountGeneralEntityList.stream().collect(Collectors.groupingBy(i -> isBlank(i.getAccountNo()) ? "" : i.getAccountNo()));

joining拼接

// 查询年龄大于19的用户名,去重后用,拼接。
String usernames = userList.stream().filter(i -> i.getAge() > 19).map(User::getUsername).distinct().collect(Collectors.joining(","));
// 将ID转为String并用逗号拼接起来。
String decIds = decHeads.stream().map(i -> i.getId().toString()).collect(Collectors.joining(","));

组合用法示例

// 获取用户名集合,用户ID不为空且去重
List<String> users = userList.stream().filter(i -> i.getUserId() != null).map(User::getUsername).distinct().collect(Collectors.toList());// 获取用户名数组,用户ID不为空且去重
String[] usersArr = userList.stream().filter(i -> i.getUserId() != null).map(User::getUsername).distinct().collect(Collectors.toList()).toArray(new String[userList.size()]);// 统计总岁数,排除用户ID是空的
int totalAge = userList.stream().filter(i -> isNotEmpty(i.getUserId())).mapToInt(User::getAge).sum();// 统计工资的数量,可设置去重
long moneyCount = userList.stream().filter(i -> isNotEmpty(i.getUserId())).map(User::getMoney).count();
long moneyCount1 = userList.stream().filter(i -> isNotEmpty(i.getUserId())).map(User::getMoney).distinct().count();// 获取用户列表,要求跳过第1条数据后的前3条数据
List<User> users1 = userList.stream().skip(1).limit(3).collect(Collectors.toList());

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

如若内容造成侵权/违法违规/事实不符,请联系郑州代理记账网进行投诉反馈,一经查实,立即删除!

相关文章

风控人应知的坏账准备金知识

无论是为金融放贷机构提供资金的资金方还是进行放贷行为的资产方&#xff0c;在整套资产管理体系中都十分关注一个名词&#xff1a;“坏账准备金”。在信贷中&#xff0c;准备金是为预期贷款损失准备的&#xff0c;因此拨备率和拨备覆盖率也由此产生。 在相关的拨备率的计算公…

【金融风控-贷款违约预测】Task4 建模与调参篇

阿里云天池学习赛 – Datawhale学习笔记 文章目录一、学习内容二、代码三、关于调参四、经验总结衔接笔记内容链接赛题&#xff1a;零基础入门数据挖掘 - 零基础入门金融风控之贷款违约预测项目地址&#xff1a;https://github.com/datawhalechina/team-learning-data-mining/t…

银行坏账数据分析

加载数据 import pandas as pd import numpy as npdata pd.read_csv(loan.csv,encodingansi) print(data) 好坏用户&#xff0c;0代表信用好用户&#xff0c;1代表信用坏用户。 data pd.read_csv(loan.csv,encodingansi) print(data.isnull().sum())对月收入数据进行填充 mod…

贷前贷中风控体系

消费金融服务方&#xff1a;金融系、场景系、互联网系 第三方支撑平台&#xff1a;获客平台、风控支持、系统服务、支付平台、贷后管理 消费金融风控全流程 贷前审查&#xff1a;信息采集、信息验证、反欺诈 贷中评估&#xff1a;信用评估、授信 贷后管理&#xff1a;贷后…

贷中风控调额方法与策略详解

信贷的互金产品归纳起来有两大产品&#xff0c;非循环贷与循环贷产品。这两类产品有差异也有相同点。既然是互金产品&#xff0c;重视贷前模块都是必然的。贷前的欺诈风险及信用风险把控&#xff0c;是在互金中最受重视的部分。 而这两个产品的区别&#xff0c;如对于非循环贷这…

混淆矩阵、错误率、正确率、精确度、召回率、F1值、PR曲线、ROC曲线、AUC

点击此处返回总目录 一、混淆矩阵 二、错误率、正确率 三、精确度、召回率 四、F1值 五、P-R曲线 六、ROC曲线 参考&#xff1a;https://www.jianshu.com/p/82903edb58dc //这篇文章写的不错&#xff0c;除了F1值那个地方有错误。 https://www.cn…

利润最大化下的模型cutoff测算

评分策略根据模型的结果制定cutoff值&#xff0c;根据不同的分数走不同的审批策略&#xff0c;或者使用不同的额度策略。cutoff值的确定可以从违约率、通过率、ks值、盈利分析等角度进行量化分析。本文基于工作中切实存在的业务痛点&#xff0c;从盈利分析的角度分析如何调整模…