Stream 流操作求和处理
1.项目中在实际操作JPA的时候,通常会结合对应的Stream流去使用,由于我个人的原因对Stream流式编程应用的不太熟练,对很多操作,都是一知半解的。下面就对Stream流在操作中用的比较多的东西做过实际的总结
采用Strema流进行数值求和的两种方式
1.直接通过mapToInt(Integer::intValue)这种形式去获取对应的值,最后去进行sum求和
python
int sum = list.stream().map(Person::getAge).mapToInt(Integer::intValue).sum();
2.通过summarizingInt这种方式去进行控制,可以更好的得出常用的平均值,最大值,最小值
ini
IntSummaryStatistics collect = list.stream().collect(Collectors.summarizingInt(Person::getAge));
Stream流操作-- Java8 Stream Collectors.toMap 和stream().map()区别
1.在使用Stream流操作的时候,还有很多地方不清楚的,比如在最终使用collect操作的时候,需要进行相关的map映射.
但是有一点不清楚的就是stream().map(),和stream().collect(CollectionsUtils.toMap());的区别
ini
Map<String, Integer> residentCountMap = residentVOS.stream().collect(Collectors.toMap(ActivityCountVO::getActivityId, ActivityCountVO::getCount));
java
List<SimpleRecommendRuleDTO> resultList =recommendRuleList.stream().map(SimpleRecommendRuleDTO::new).collect(Collectors.toList());
- list.stream().map()
取出来某个值
ini
List<SchemePriceDTO> ftiPriceDtos = ftiResourcePriceDTOS.stream()
.map(x -> x.getPrice()).collect(Collectors.toList());
从list中取出某个对象
ini
List<EventDetail> eventDetailList= request.getEventDto().getEventDetails().stream().map(detail -> {
EventDetail eventDetail = new EventDetail();
eventDetail.setGroupDetailId(detail.getGroupDetailId());
eventDetail.setOrderId(detail.getOrderId());
return eventDetail;
}).collect(Collectors.toList());
- Collectors.toMap 是把list转化为Map
ini
Map<String, HLogHBasePO> hLogHBasePOMap =
hLogHBasePOs.stream().collect(Collectors.toMap(k -> k.getLogId(), v -> v));
可以看出来上述的操作中.stream().map()是取值的操作,而Collectors.toMap()是转换的操作
下面的demo可以进一个操作
csharp
List<Person> list = new ArrayList<>();
list.add(new Person(22, "xiaohong"));
list.add(new Person(33, "xiaohong2"));
list.add(new Person(44, "xiaohong3"));
List<String> strings = list.stream().map(Person::getName).collect(Collectors.toList());
Map<String, Person> personMap = list.stream().collect(Collectors.toMap(Person::getName, Function.identity()));
System.out.println("将list转换为map"+personMap);
System.out.println("取出list集合中的值,然后讲name组成一个集合"+strings);
下面我在项目中见的比较多地方在进行记录一下可以看到,stream().map,和Collectors.toMap()在实际中的区别
stream().map()通常会结合对应的Collectors.toMap进行联合应用
java
List<ResidentReceiveDTO> resultList = residentReceive.getContent().stream().map(ResidentReceiveDTO::new).collect(Collectors.toList());
List<String> sitIds = resultList.stream().map(ResidentReceiveDTO::getSiteId).collect(Collectors.toList());
List<Site> sites = siteRepository.findAllById(sitIds);
Map<String, Site> siteMap = sites.stream().collect(Collectors.toMap(Site::getId, Function.identity()));
1.分析一下代码可以看到,第一行的主要思想是将对应的一个数据实体list,转换成为一个dto的list实体集。
2.下面转换完之后,在将dto 的list实体集取出里面的id属性字段在组合成一个list的Id属性集
3.之后就根据对应的ID的list集合去查询全部的实体list集合,通过全部的实体list集合就可以返回一map映射的列表对象
4.后面这个转换的是,就是结合Collectors.toMap(sIT::getId,Function.identity()),这个Function.identity()这个属性字段通常用来作为value,这个是什么意思呢
官方的解释很笼统:Java 8允许在接口中加入具体方法。接口中的具体方法有两种,default方法和static方法,identity()就是Function接口的一个静态方法。
Function.identity()返回一个输出跟输入一样的Lambda表达式对象,等价于形如t -> t形式的Lambda表达式。
下面通过搜查资料发现这个Function.identity()方法返回的就是自己;
identity() 方法JDK源码如下:
javascript
static Function identity() {
return t -> t;
}
展示一个按理来进行操作
arduino
// 将Stream转换成容器或Map
Stream<String> stream = Stream.of("I", "love", "you", "too");
Map<String, Integer> map = stream.collect(Collectors.toMap(Function.identity(), String::length));
Function.identity()的应用
下面的代码中,Task::getTitle需要一个task并产生一个仅有一个标题的key。task -> task是一个用来返回自己的lambda表达式,上例中返回一个task。
arduino
private static Map<String, Task> taskMap(List<Task> tasks) {
return tasks.stream().collect(toMap(Task::getTitle, task -> task));
}
Function.identity() or t->t?
rust
Arrays.asList("a", "b", "c")
.stream()
.map(Function.identity()) // <- This,
.map(str -> str) // <- is the same as this.
.collect(Collectors.toMap(
Function.identity(), // <-- And this,
str -> str)); // <-- is the same as this.
上面的代码中,为什么要使用Function.identity()代替str->str呢?它们有什么区别呢?
在上面的代码中str -> str和Function.identity()是没什么区别的因为它们都是t->t。但是我们有时候不能使用Function.identity,看下面的例子:
ini
List list = new ArrayList<>();
list.add(1);
list.add(2);
下面这段代码可以运行成功:
ini
int[] arrayOK = list.stream().mapToInt(i -> i).toArray();
但是如果你像下面这样写:
ini
int[] arrayProblem = list.stream().mapToInt(Function.identity()).toArray();
运行的时候就会错误,因为mapToInt要求的参数是ToIntFunction类型,但是ToIntFunction类型和Function没有关系。
(实际应用:)
可以看到了这个Function.identity()指的就是Regiser中具体的实体类
数据库操作
1.单个处理只有在用id查详情的时候会用到,但大部分业务都是批量操作的
大部分情况下,在进行操作的时候,很少会有进行findById并返回单个实体的这种操作情况,一般情况都是批量操作的这种情况,业务处理基本上入参都是ids,出参也是list集合这种,这个时候就需要进行findByidIn
arduino
List<Resident> findAllByDelFlagIsFalseAndIdIn(List<String> ids);
ini
List<Resident> residents = residentRepository.findAllByDelFlagIsFalseAndIdIn(residentIds);
可以看到对应的相关的findByIdIn对应的相关的集合的内容都是通过批量查询进行操作的,在进行相关的业务操作的时候最好进行findByIdIn这种的操作方式进行操作
2.通常给DTO添加额外的字段需要进行补充的时候,可以采用下面的这种方式进操作,并且一般情况下不要在for循环中进行查询操作,这样的话可能会造成代码抛异常的情况,这种情况下就需要进行特殊的处理,但是正常的情况给DTO赋值其他字段有需要对应的主键ID,通过对应的循环实体里面的ID,然后再结合其他的查询获取到其他的DTO,给循环体里面的DTO赋值,这种操作一般都是按如下的方式进行处理操作;
ini
List<String> residentIds = resultList.stream().map(ResidentReceiveDTO::getResidentId).collect(Collectors.toList());
List<Resident> residents = residentRepository.findAllByDelFlagIsFalseAndIdIn(residentIds);
Map<String, Resident> residentMap = residents.stream().collect(Collectors.toMap(Resident::getId, Function.identity()));
List<String> sitIds = resultList.stream().map(ResidentReceiveDTO::getSiteId).collect(Collectors.toList());
List<Site> sites = siteRepository.findAllByDelFlagIsFalseAndIdIn(sitIds);
Map<String, Site> siteMap = sites.stream().collect(Collectors.toMap(Site::getId, Function.identity()));
resultList.forEach(l -> {
Activity activity = activityService.findById(l.getActivityId());
Resident resident = residentMap.get(l.getResidentId());
Site site = siteMap.get(l.getSiteId());
if (resident!=null){
l.setResidentName(resident.getName());
l.setCardType(resident.getCardType());
l.setCardNo(resident.getCardNo());
}
if (site!=null){
l.setSiteName(site.getName());
}
if(activity!=null){
l.setActivityName(activity.getTitle());
l.setProductName(activity.getProductName());
}
l.setPersonName(site.getAdminName());
l.setCount(Arrays.stream(l.getProductNo().split(",")).count());
});
通过主要的分析和概述之后,主要的特征为三部分的代码,
1.第一部分代码为,先将对应的DTO里面要设值的其他字段的ID部分拿出来,通常来说这个DTO里面的ID字段,可以同这个查询其他的实体,就像我注释中写的那样,但是那样很不规范。
2.经过改造之后,可以拿到DTO里面所有的IDS的属性字段的集合,然后在外面通过findByIDin可以拿到所有根据这个ID有关的实体的数据,可能是多条数据,
3.第三步,就是通过查出来的IDS的实体的集合,在进行转换,将对应的list转换成map的形式,这个时候就需要通过key,value的形式控制,在控制的是,key可以设置成这个IDS实体集中实体的ID字段,value可以进行设置为这个实体,进行映射额,那这个形式就需要通过Function.identity()这个通常就是返回对象自己的。
通常来说使用SpringDataJPA,必须要集合stream流操作,如果stream流不熟悉,在进行使用JPA的时候,在联合操作的时候会出现很多问题。
后面还是有很多不足的地方,还需要进行补充和提升