【java】入坑Stream,开发效率窜三窜
在jdk1.8之前,我们对于集合的处理都是比较麻烦的,比如:做一次过滤,就会在代码中使用for进行处理。jdk1.8后引入了Stream API来处理集合,使其变得简单。
1、Stream简介
Stream:流,可以对集合进行操作,比如:顾虑,合并等,是一种高效且易于使用处理数据的方法。
在Stream操作中分为三个步骤:
1、创建Stream流:比如:Stream.of()等
2、中间操作:即处理Stream流,比如:filter,map等
3、终止操作:即结束Stream流,返回操作结果,比如:collect(Collectors.toList())
在操作Stream时,Stream自己不会存储元素,不会改变原来对象,会延迟执行,只会在需要结果时才执行。
2、Stream常用方法
准备工作,创建一个专家实体,便于进行方法操作。
/**
* @author: jiangjs
* @description:
* @date: 2022/7/15 15:37
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Expert {
private String name;
private String gender;
private Integer age;
}
创建一个集合:
List<Expert> experts = Arrays.asList(
new Expert("jiashn","男",20),
new Expert("张三-zhangsan","女",21),
new Expert("王五-wangwu","女",26),
new Expert("李四-lisi","男",24),
new Expert("李四-lisi","男",24));
2.1 创建Stream
stream()或parallelStream()
:集合通过stream()可以创建顺序流,parallelStream()创建并行流。
experts.stream()
experts.parallelStream()
Stream.of()
:将数组转化成Stream流。
Stream<Expert> expertStream = Stream.of(new Expert("赵一-zhaoyi", "男", 20),
new Expert("王定六-wangdingliu", "男", 21));
2.2 Stream中间操作
2.2.1 filter
filter(Predicate p)
:用于过滤满足条件的数据,例如:上述专家中查找年龄小于等于25岁的人员。
//过滤年龄小于等于25的人
List<Expert> filterExperts = experts.stream().filter(expert -> expert.getAge() <= 25).collect(Collectors.toList());
System.out.println("年龄小于等于25岁的人的信息:" + filterExperts);
输出:
年龄小于25岁的人的信息:[Expert(name=jiashn, gender=男, age=20), Expert(name=张三-zhangsan, gender=女, age=21), Expert(name=李四-lisi, gender=男, age=24)]
2.2.2 map和flatMap
map(Function f)
:将每个元素映射成新的元素,用于获取集合中某个元素的数据信息,例如:获取所有专家的名字。
//获取所以成员的名字信息
String names = experts.stream().map(Expert::getName).collect(Collectors.joining(","));
System.out.println("所有人员的名称:" + names);
输出:
所有人员的名称:jiashn,张三-zhangsan,王五-wangwu,李四-lisi
flatMap(Function<? super T, ? extends Stream<? extends R>> mapper)
:将流中每个值换成另一个流,并将所有流汇成一个流。例如:拆分名字,并获取名字信息。
//拆分名字
List<String> splitName = experts.stream().flatMap(exp -> Stream.of(exp.getName().split("-")))
.collect(Collectors.toList());
System.out.println("拆分名字结果:" + splitName);
输出:
拆分名字结果:[jiashn, 张三, zhangsan, 王五, wangwu, 李四, lisi]
2.2.3 sorted
sorted()
:排序,默认是升序排序,会产生一个新的流
sorted(Comparator<? super T> comparator)
:排序,按照比较器顺序排序,会产生一个新的流。例如:按照年龄进行排序
//年龄排序,正序或倒序
List<Expert> sortInfo = experts.stream().sorted(Comparator.comparing(Expert::getAge))
.collect(Collectors.toList());
List<Expert> reversedInfo = experts.stream().sorted(Comparator.comparing(Expert::getAge).reversed())
.collect(Collectors.toList());
System.out.println("人员年龄排序(升序):" + sortInfo+";人员年龄排序(降序):"+reversedInfo);
输出:
人员年龄排序(升序):[Expert(name=jiashn, gender=男, age=20), Expert(name=张三-zhangsan, gender=女, age=21), Expert(name=李四-lisi, gender=男, age=24), Expert(name=王五-wangwu, gender=女, age=26)];
人员年龄排序(降序):[Expert(name=王五-wangwu, gender=女, age=26), Expert(name=李四-lisi, gender=男, age=24), Expert(name=张三-zhangsan, gender=女, age=21), Expert(name=jiashn, gender=男, age=20)]
在比较器中使用 .reversed()
实现排序降序。
2.2.4 distinct()
distinct()
:去重,通过流所生成的hashCode()和equals()去除重复元素。例如:去重上面集合中的李四.
//去重
List<Expert> disExperts = experts.stream().distinct()
.collect(Collectors.toList());
System.out.println("去重:" + disExperts);
输出:
去重:[Expert(name=jiashn, gender=男, age=20), Expert(name=张三-zhangsan, gender=女, age=21), Expert(name=王五-wangwu, gender=女, age=26), Expert(name=李四-lisi, gender=男, age=24)]
2.2.5 limit、skip
limit(long maxSize)
:截断当前流,获取不超过给定数量的元素。
skip(long n)
:跳过元素,扔掉下标从0开始到n的元素的流,如果流中元素个数不超n个,则返回一个空流,与limit()互补。例如:获取下标从2开始的2个元素。
//截取记录信息
List<Expert> twoInfos = experts.stream().skip(2).limit(2).collect(Collectors.toList());
System.out.println("截取记录:"+twoInfos);
输出:
截取记录:[Expert(name=王五-wangwu, gender=女, age=26), Expert(name=李四-lisi, gender=男, age=24)]
我们也可以使用skip、limit的组合来对返回回来的list数据进行分页操作。
2.3 Stream终止操作
终端操作从流的流水线生成结果。
2.3.1 allMatch、anyMatch、noneMatch
allMatch(Predicate p)
:检查集合中所有元素是否与当前条件相匹配。例如:验证当前集合中元素性别是否都是男。
anyMatch(Predicate p)
:检查当前集合中是否存在元素与当前条件相匹配。例如:验证当前集合中元素是否存在性别男。
noneMatch(Predicate p)
:检查当前集合元素是否所有元素与当前条件不匹配。例如:验证当前集合所有元素性别都不为男。
//allMatch
boolean allMatch = experts.stream().allMatch(expert -> Objects.equals(expert.getGender(), "男"));
System.out.println("是否性别都为男:"+allMatch);
//anyMatch
boolean ageMatch = experts.stream().anyMatch(expert -> Objects.equals(expert.getGender(), "男"));
System.out.println("是否存在性别为男:"+ageMatch);
//noneMatch
boolean noneMatch = experts.stream().noneMatch(expert -> Objects.equals(expert.getGender(), "男"));
System.out.println("所有元素性别不为男:"+noneMatch);
输出:
是否性别都为男:false
是否存在性别为男:true
所有元素性别不为男:false
2.3.2 findFirst、findAny()
findFirst()
:获取集合中的第一个元素信息,例如:获取集合第一个元素信息的姓名。
findAny()
:获取流中的任意元素,具有不确定性。
//findFirst
String name = experts.stream().findFirst().orElseGet(Expert::new).getName();
System.out.println("获取第一个元素的姓名:"+name);
//findAny
String anyName = experts.stream().findAny().orElseGet(Expert::new).getName();
System.out.println("获取符合条件任意元素的姓名:"+anyName);
输出:
获取第一个元素的姓名:jiashn
获取符合条件任意元素的姓名:jiashn
2.3.3 count
count()
:统计流中元素个数,可以与filter进行使用来统计符合条件的元素个数。例如:统计年龄大于23岁的人员个数
//count
long count = experts.stream().filter(expert -> expert.getAge() > 23).count();
System.out.println("年龄大于23岁的人员个数:"+count);
输出:
年龄大于23岁的人员个数:3
2.3.4 max、min
max(Comparator c)
:返回流中符合条件的最大值。例如:获取集合年龄最大的元素信息。
min(Comparator c)
:返回流中符合条件的最小值。例如:获取集合年龄最小的元素信息。
//max
Expert maxExpert = experts.stream().max(Comparator.comparing(Expert::getAge)).get();
System.out.println("年龄最大人员信息:"+maxExpert);
//min
Expert minExpert = experts.stream().min(Comparator.comparing(Expert::getAge)).get();
System.out.println("年龄最小人员信息:"+minExpert);
输出:
年龄最大人员信息:Expert(name=王五-wangwu, gender=女, age=26)
年龄最小人员信息:Expert(name=jiashn, gender=男, age=20)
2.3.5 forEach
forEach(Consumer c)
:内部循环,例如获取所有元素的姓名
//forEach
StringJoiner sj = new StringJoiner(",");
experts.forEach(expert -> sj.add(expert.getName()));
System.out.println("所有人员姓名:"+sj.toString());
输出:
所有人员姓名:jiashn,张三-zhangsan,王五-wangwu,李四-lisi,李四-lisi
当然也可以使用map,Collectors.joining(",")
实现上述功能,参见map的使用。
2.3.6 reduce
reduce(T iden, BinaryOperator b)
:将流中元素反复结合起来,得到一个值,返回T
reduce(BinaryOperator b)
:将流中元素反复结合起来,得到一个值,返回Optional。例如:获取所有人员年龄的总和
//reduce
int totalAge = experts.stream().mapToInt(Expert::getAge).reduce(0, (total, age) -> {
total += age;
return total;
});
System.out.println("所有人员年龄总和:"+totalAge);
输出:
所有人员年龄总和:115
2.3.7 collect(Collector c)
collect(Collector c)
:将流转换成其他形式。例如:list,set等。常用的方法:
toList
:将流转换成list集合输出。上述例子中很多就用到
toSet
:将流转换成set集合输出。例如:获取姓名
joining
:连接流中每个元素,返回字符串,例如:运用map中的提到的获取所有用户姓名,使用","连接
groupingBy
:分组,根据某些元素进行分组,例如:根据性别进行分组
partitioningBy
:分区,根据true或false进行分区。例如:根据年龄大于23进行分区
summarizingDouble
:汇总,统计元素的最大值,最小值等,例如:根据年龄进行汇总
当然stream还提供了其他的方法,如:counting,summingInt等。
//toSet
Set<String> nameSet = experts.stream().map(Expert::getName).collect(Collectors.toSet());
System.out.println("所有姓名:"+nameSet);
//groupingBy
Map<String, List<Expert>> genderMap = experts.stream().collect(Collectors.groupingBy(Expert::getGender));
System.out.println("性别分组信息:"+genderMap);
//summarizingDouble
DoubleSummaryStatistics statistics = experts.stream().collect(Collectors.summarizingDouble(Expert::getAge));
System.out.println("年龄最大值:"+statistics.getMax());
System.out.println("年龄最小值:"+statistics.getMin());
System.out.println("年龄平均值:"+statistics.getAverage());
System.out.println("年龄总和值:"+statistics.getSum());
System.out.println("总人数:"+statistics.getCount());
//partitioningBy
Map<Boolean, List<Expert>> collect = experts.stream().collect(Collectors.partitioningBy(jia -> jia.getAge() > 23));
List<Expert> gtExpert= collect.get(Boolean.TRUE);
List<Expert> ltExpert= collect.get(Boolean.FALSE);
System.out.println("年龄大于23岁的数据:"+gtExpert);
System.out.println("年龄小于等于23岁的数据:"+ltExpert);
输出:
所有姓名:[jiashn, 张三-zhangsan, 王五-wangwu, 李四-lisi]
性别分组信息:{女=[Expert(name=张三-zhangsan, gender=女, age=21), Expert(name=王五-wangwu, gender=女, age=26)], 男=[Expert(name=jiashn, gender=男, age=20), Expert(name=李四-lisi, gender=男, age=24), Expert(name=李四-lisi, gender=男, age=24)]}
年龄最大值:26.0
年龄最小值:20.0
年龄平均值:23.0
年龄总和值:115.0
总人数:5
年龄大于23岁的数据:[Expert(name=王五-wangwu, gender=女, age=26), Expert(name=李四-lisi, gender=男, age=24), Expert(name=李四-lisi, gender=男, age=24)]
年龄小于等于23岁的数据:[Expert(name=jiashn, gender=男, age=20), Expert(name=张三-zhangsan, gender=女, age=21)]
jdk1.8中的Stream的出现,让我们对集合的操作变得简单,业精于勤荒于嬉,我们多多使用,自然会对这些方法使用熟练掌握。
转载自:https://juejin.cn/post/7229508679777959991