likes
comments
collection
share

【java】入坑Stream,开发效率窜三窜

作者站长头像
站长
· 阅读数 18

在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的出现,让我们对集合的操作变得简单,业精于勤荒于嬉,我们多多使用,自然会对这些方法使用熟练掌握。