⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 blog.csdn.net/qq_35634181/article/details/108867857 「goodluckwj」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

ExportTemperatureDto实体对象:

@Getter
@Setter
@ToString
public class ExportTemperatureDto {
private String name;
private Double morningTemperature;
private Double afternoonTemperature;
private String classId;
private String gradeId;
private Integer personId;
}

在一个ExportTemperatureDto的集合中,根据personId属性去重,生成一个新的集合。

import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;

public class StreamTest {

public static void main(String[] args) {
List<ExportTemperatureDto> temperatureList = Lists.newArrayList();
temperatureList.add(new ExportTemperatureDto(1, "haha"));
temperatureList.add(new ExportTemperatureDto(2, "haha"));
temperatureList.add(new ExportTemperatureDto(3, "haha"));
temperatureList.add(new ExportTemperatureDto(4, "haha"));

temperatureList.add(new ExportTemperatureDto(1, "hahaasdas"));
temperatureList.add(new ExportTemperatureDto(2, "hahaasdas"));

List<ExportTemperatureDto> result = temperatureList.stream()
.collect(
collectingAndThen(
toCollection(
() -> new TreeSet<>(comparing(ExportTemperatureDto::getPersonId))
),
ArrayList::new
)
);

result.forEach(System.out::println);

/*
输出结果为:
personId为1的,其名称为haha
personId为2的,其名称为haha
因为TreeSet底层是使用TreeMap进行实现的,传入了根据getPersonId进行比较的比较器
在判断personId相同时,其比较结果为0,然后就会替换其value值,而key值是不会变化的,
又因为TreeSet是将传入的元素作为key的,所以使用TreeSet时,当比较器比较的结果相同时,以不会将原来的值替换成比较后的值
*/

}
}

知其然知其所以然,这个stream流的操作看起来还是有点难度的,这里记录一下。

使用到了collectingAndThen完成根据属性进行去重的操作,对于该去重操作的关键使用到了collectingAndThen、toCollection、TreeSet,有点难以理解,当时我也是懵逼的,这里记录一下,以后肯定还会用的到。

理解根据对象的属性进行去重的核心是,将集合放到TreeSet中,然后再将TreeSet转为List, 其中TreeSet要传入一个根据哪个属性进行比较的比较器,然后使用public ArrayList(Collection<? extends E> c)将TreeSet放入构造器中生成List。

上面的Stream操作可以使用普通的集合:

TreeSet<ExportTemperatureDto> treeSet = new TreeSet<>(Comparator.comparing(ExportTemperatureDto::getPersonId));
for (ExportTemperatureDto temperatureDto : temperatureList){
treeSet.add(temperatureDto);
}
List<ExportTemperatureDto> result2 = new ArrayList<>(treeSet);

只要能够理解普通集合怎么操作的,那么使用Stream流操作时,就是要看对于API的使用是否熟悉,其实这个才是关键,只有理解了collectingAndThen、toCollection、JDK8的匿名函数这样内容,才能看懂这个式子。

下面就简单介绍一下:

首先说一下collectingAndThen方法的使用-------先进行结果集的收集,然后将收集到的结果集进行下一步的处理,红字的两句话是理解collectingAndThen的关键,首先看一下collectingAndThen需要传递的参数:

public static<T,A,R,RR> Collector<T,A,RR> 
collectingAndThen(Collector<T,A,R> downstream,
Function<R,RR> finisher)

可以看到第一个参数是Collector接口的子类,所以还是对于对于Collector的处理,Collectors工具类里面的toList()toSet()joining()mapping()collectingAndThen()等几乎所有的方法都可以使用,这样感觉这个collectingAndThen就很强大了,可以嵌套的去使用。

第二个参数是一个Function函数,熟悉的同学都知道,Function函数是这样的:R apply(T t),这个也是理解上面去重式子的关键,原来我想的是ArrayList::new调用的无参的构造方法,其实他调用的ArrayList的有参构造方法,

public ArrayList(Collection<? extends E> c)

调用的是上面那个构造方法,这样就很清晰,就是把第一个参数downstream的结果,交给第二个参数Function函数的参数里面,R apply(T t),也就是将结果设置成t。

对于toCollection是一个通用的转为集合的操作,当然在Collectors类里面也有toList()toSet()方法,但是都不满足于使用TreeSet来收集集合的方法,所以使用toCollection是一个通用的方法,使用TreeSet进行收集,然后传入根据哪个属性进行比较的比较器,这样就可以了。

文章目录