Stream 实战案例
java
it书童
2021-01-14 16:22:40
0赞
0踩
1294阅读
0评论
案例1
班级中有20名学生,每名学生有5门课的考试成绩,其中缺考的科目分数字段为空。需要找出有缺考的学生叫什么名字
package stream.cases;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CaseOne {
@Data
@AllArgsConstructor
class ExamStudentScore {
private String studentName;
private Integer scoreValue;
private String subject;
}
// 学生考试成绩
Map<String, List<ExamStudentScore>> studentMap;
@Before
public void init() {
studentMap = new HashMap<>();
List<ExamStudentScore> zsScoreList = new ArrayList<>();
zsScoreList.add(
new ExamStudentScore(
"张三",
30,
"CHINESE"));
zsScoreList.add(
new ExamStudentScore(
"张三",
40,
"ENGLISH"));
zsScoreList.add(
new ExamStudentScore(
"张三",
50,
"MATHS"));
studentMap.put("张三", zsScoreList);
List<ExamStudentScore> lsScoreList = new ArrayList<>();
lsScoreList.add(
new ExamStudentScore(
"李四",
80,
"CHINESE"));
lsScoreList.add(
new ExamStudentScore(
"李四",
null,
"ENGLISH"));
lsScoreList.add(
new ExamStudentScore(
"李四",
100,
"MATHS"));
studentMap.put("李四", lsScoreList);
List<ExamStudentScore> wwScoreList = new ArrayList<>();
wwScoreList.add(
new ExamStudentScore(
"王五",
null,
"CHINESE"));
wwScoreList.add(
new ExamStudentScore(
"王五",
null,
"ENGLISH"));
wwScoreList.add(
new ExamStudentScore(
"王五",
70,
"MATHS"));
studentMap.put("王五", wwScoreList);
}
@Test
public void findStudent() {
studentMap.forEach((studentName, scoreList) -> {
boolean bool = scoreList.stream()
.anyMatch(score -> {
return score.getScoreValue() == null;
});
if (bool) {
System.out.println("此学生[" + studentName + "]有缺考情况");
}
});
}
}
结果:
此学生[李四]有缺考情况
此学生[王五]有缺考情况
案例2
标签管理功能模块:允许用户批量添加标签,后台需要对标签去重,并且需要防止数据库中存在同名的标签
package stream.cases;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
public class CaseTwo {
/**
* 用户请求的创建标签模型
*/
@Data
@AllArgsConstructor
class TagReqDTO {
private String name;
private Integer age;
}
/**
* 从DB中查询出来的已经存在的标签名
*/
List<String> tagListFromDB;
/**
* 用户请求的标签列表
*/
List<TagReqDTO> tagListFromReq;
@Before
public void init() {
// 数据库中存在的标签名列表
tagListFromDB = Lists.newArrayList(
"李四", "王五", "赵六");
// 用户提交的
tagListFromReq = Lists.newArrayList(
new TagReqDTO("张三", 10),
new TagReqDTO("李四", 30),
new TagReqDTO("张三", 10));
}
@Test
public void distinctTag() {
tagListFromReq.stream()
// true:通过测试,数据不过滤;false:未通过测试,数据被过滤
.filter(tag -> !tagListFromDB.contains(tag.getName()))
// 使用equals对元素进行比较
.distinct()
.forEach(System.out::println);
}
}
结果:
CaseTwo.TagReqDTO(name=张三, age=10)
案例3
权限管理功能模块:查询某用户所有角色下所包含的权限名称
package stream.cases;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class CaseThree {
/**
* 角色
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
class Role {
// 权限列表
private List<Permission> permissions;
}
/**
* 权限
*/
@Data
@AllArgsConstructor
class Permission {
// 权限名称
private String name;
}
// 用户角色列表
List<Role> roleList;
@Before
public void init() {
roleList = new ArrayList();
Role adminRole = new Role();
List<Permission> adminPermissionList = Lists.newArrayList(
new Permission("删除"),
new Permission("查看"),
new Permission("导出"));
adminRole.setPermissions(adminPermissionList);
Role userRole = new Role();
List<Permission> userPermissionList = Lists.newArrayList(
new Permission("新建"),
new Permission("修改"),
new Permission("删除"),
new Permission("查看"));
userRole.setPermissions(userPermissionList);
roleList.add(adminRole);
roleList.add(userRole);
}
@Test
public void findPermission() {
List<Permission> collect = roleList.stream()
// 扁平化MAP 获取对象中的集合类属性,组成一个新的流
.flatMap(role -> role.getPermissions().stream())
// peek 与 forEach 类似,区别是用在中间过程中,后面可以接其他操作
.distinct()
.collect(Collectors.toList());
System.out.println(JSON.toJSONString(collect, true));
}
}
结果:
[
{
"name":"删除"
},
{
"name":"查看"
},
{
"name":"导出"
},
{
"name":"新建"
},
{
"name":"修改"
}
]
案例4
设计一个对外提供服务的接口,支持调用方传入多个账户编号查询订单
package stream.cases;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class CaseFour {
@Data
@AllArgsConstructor
class Order {
private Integer orderId;
private String accountId;
}
/**
* 模拟数据库查询
*
* @param accountIds
* @return
*/
public List<Order> selectFromDB(List<String> accountIds) {
List<Order> orderList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
orderList.add(
new Order(i,
accountIds.get(i % accountIds.size())));
}
return orderList;
}
/**
* 接口
*
* @param accountIds
* @return
*/
public Map<String, List<Order>> queryOrderByAccountIds(
List<String> accountIds) {
return Optional.ofNullable(selectFromDB(accountIds))
.map(List::stream)
.orElseGet(Stream::empty)
// group分组功能
.collect(Collectors.groupingBy(
Order::getAccountId)
);
}
@Test
public void test() {
Map<String, List<Order>> orders = queryOrderByAccountIds(
Lists.newArrayList("张三", "李四", "王五")
);
System.out.println(JSON.toJSONString(orders, true));
}
}
结果:
{
"李四":[
{
"accountId":"李四",
"orderId":1
},
{
"accountId":"李四",
"orderId":4
},
{
"accountId":"李四",
"orderId":7
}
],
"张三":[
{
"accountId":"张三",
"orderId":0
},
{
"accountId":"张三",
"orderId":3
},
{
"accountId":"张三",
"orderId":6
},
{
"accountId":"张三",
"orderId":9
}
],
"王五":[
{
"accountId":"王五",
"orderId":2
},
{
"accountId":"王五",
"orderId":5
},
{
"accountId":"王五",
"orderId":8
}
]
}
案例5
在股票中,撮合交易的原则是一段时间内的交易申请,价格越高的先成交;价格一样,下单时间最早的先成交;价格和时间一致,交易量大的先成交;如何价格、时间和交易量都一致,机构优先成交,散户最后成交。
现有一批交易申请数据,需要确认交易先后顺序。
package stream.cases;
import com.alibaba.fastjson.JSON;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Before;
import org.junit.Test;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
public class CaseFive {
/**
* 交易实体模型
*/
@Data
@AllArgsConstructor
static class Trade {
// 下单价格
private BigDecimal price;
// 下单时间
private LocalDateTime time;
// 下单量
private Integer count;
// 下单类型:机构 / 个人
private String type;
}
/**
* 一段时间内的交易申请
*/
List<Trade> trades;
@Before
public void init() {
trades = new ArrayList<>();
trades.add(new Trade(new BigDecimal(100),
// 在当前时间的基础上添加 1 秒
LocalDateTime.now().plusSeconds(1),
500, "机构"));
trades.add(new Trade(new BigDecimal(101),
LocalDateTime.now().plusSeconds(2),
1, "个人"));
trades.add(new Trade(new BigDecimal(101),
LocalDateTime.now().plusSeconds(1),
1, "个人"));
trades.add(new Trade(new BigDecimal(100),
LocalDateTime.now().plusSeconds(1),
500, "个人"));
trades.add(new Trade(new BigDecimal(100),
LocalDateTime.now().plusSeconds(0),
2, "个人"));
trades.add(new Trade(new BigDecimal(100),
LocalDateTime.now().plusSeconds(0),
100, "机构"));
}
@Test
public void sortTrade() {
System.out.println("排序前数据~~~\n" + JSON.toJSONString(trades, true));
List<Trade> sorted = trades.stream()
.sorted(
Comparator
// 首先按照价格排序
.comparing(
Trade::getPrice,
// 进行排序调整,将自然排序翻转
Comparator.reverseOrder())
// 时间先后进行排序,自然排序
.thenComparing(Trade::getTime)
// 交易量排序,自然排序翻转
.thenComparing(
Trade::getCount,
Comparator.reverseOrder())
// 自定义排序规则
.thenComparing(
// 要排序的字段值
Trade::getType,
// 自定义排序规则
(type1, type2) -> {
if ("机构".equals(type1) && "个人".equals(type2)) {
// -1:type1在先, type2在后
return -1;
} else if ("个人".equals(type1) && "机构".equals(type2)) {
return 1;
} else {
return 0;
}
}))
.collect(Collectors.toList());
System.out.println("排序后结果~~~\n" + JSON.toJSONString(sorted, true));
}
}
结果:
排序前数据~~~
[
{
"count":500,
"price":100,
"time":"2021-01-10T18:24:34.330",
"type":"机构"
},
{
"count":1,
"price":101,
"time":"2021-01-10T18:24:35.330",
"type":"个人"
},
{
"count":1,
"price":101,
"time":"2021-01-10T18:24:34.330",
"type":"个人"
},
{
"count":500,
"price":100,
"time":"2021-01-10T18:24:34.330",
"type":"个人"
},
{
"count":2,
"price":100,
"time":"2021-01-10T18:24:33.330",
"type":"个人"
},
{
"count":100,
"price":100,
"time":"2021-01-10T18:24:33.330",
"type":"机构"
}
]
排序后结果~~~
[
{
"count":1,
"price":101,
"time":"2021-01-10T18:24:34.330",
"type":"个人"
},
{
"count":1,
"price":101,
"time":"2021-01-10T18:24:35.330",
"type":"个人"
},
{
"count":100,
"price":100,
"time":"2021-01-10T18:24:33.330",
"type":"机构"
},
{
"count":2,
"price":100,
"time":"2021-01-10T18:24:33.330",
"type":"个人"
},
{
"count":500,
"price":100,
"time":"2021-01-10T18:24:34.330",
"type":"机构"
},
{
"count":500,
"price":100,
"time":"2021-01-10T18:24:34.330",
"type":"个人"
}
]
- 上一篇: 流的归约与汇总
- 下一篇: Google Guava 工具集

关于我
一个文科出身的程序员,追求做个有趣的人,传播有价值的知识,微信公众号主要分享读书思考心得,不会有代码类文章,非程序员的同学请放心订阅
转载须注明出处:https://www.itshutong.com/articles/1028
精品付费
这一次,真正掌握composer
2679
0
个人开发者通过payjs接入微信支付
4928
0
相关推荐
Java 的 Scanner 对象
724
0
Java 面向对象的多态特征介绍
756
0
Java Date 类介绍
702
0
spring 用于注入数据的注解
877
0
spring 基于注解的 AOP 实现事务控制
798
0
spring MVC 入门程序构建介绍
822
0
idea 安装 vue.js 插件
1199
0
Java 服务调用方式
861
0
Feign 入门介绍
754
0
SpringMvc 拦截器介绍及入门演示
995
0
java 异常处理机制入门
1153
0
迪米特原则
1069
0
简单工厂
1004
0
流的终端操作
1796
0