stream操作

1准备数据

复制代码
@Data
public class People {
    private String name;
    private Integer age;
    private String sex;

    public People(){ }
   
    public People(String name,Integer age,String sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    public static List<People> listDemoPeople(){
        List<People> list = new ArrayList<>();
        list.add(new People("Jack",20,"boy"));
        list.add(new People("Daniel",10,"boy"));
        list.add(new People("Lucy",10,"girl"));
        list.add(new People("Tom",40,"boy"));
        list.add(new People("Nancy",30,"girl"));
        return list;
    }
}

2.filter()

复制代码
 @Test
    public void test(){
        List<People> list = People.listDemoPeople();
        List<People> girls = list.stream().filter(p->p.getSex().equals("girl")).toList();
        System.out.println(girls);
    }
输出:
[People(name=Lucy, age=10, sex=girl), People(name=Nancy, age=30, sex=girl)]

注意:后面的.toList();返回是一个不可变list;

改成.collect(Collectors.toList());就是可变list;

List girls = list.stream().filter(p->p.getSex().equals("girl")).collect(Collectors.toList());

还有一点要注意,filter()里面写法是lambda表达式,写法简洁,但是要注意null,如果有的sex为null,就会报错。

List girls = list.stream().filter(p->p.getSex().equals("girl")).toList();

3.distinct()

distinct会用equals比较,Peope类需要重写equalst和hashCode两个方法,要保证equals为true时hashCode必须相等。我这里定义如果age相同,People就相同。

复制代码
@Override
    public boolean equals(Object p){
        People o = (People) p;
        if(this.age.equals(o.getAge())){
            return true;
        }else {
            return false;
        }
    }

    @Override
    public int hashCode(){
        return this.getAge();
    }
    
@Test
    public void distinct(){
        List<People> list = People.listDemoPeople();
        List<People> girls = list.stream().distinct().toList();
        System.out.println(girls);
    }

输出:结果中age各不相同
[People(name=Jack, age=20, sex=boy), 
People(name=Daniel, age=10, sex=boy), 
People(name=Tom, age=40, sex=boy), 
People(name=Nancy, age=30, sex=girl)]

4.limit()和sorted

limit(n),输出n条数据,我这里输出一条

复制代码
 @Test
    public void filter(){
        List<People> list = People.listDemoPeople();
        List<People> girls = list.stream()
                .filter(p->p.getSex().equals("girl"))
                .limit(1)
                .toList();
        System.out.println(girls);
    }
    输出:
    [People(name=Lucy, age=10, sex=girl)]

注意limit(n), 如果stream中的数据是排好序的会输出前n条数据

复制代码
public void filter(){
        List<People> list = People.listDemoPeople();
        List<People> girls = list.stream()
                .sorted(Comparator.comparing(People::getAge))
                .limit(3)
                .toList();
        System.out.println(girls);
    }
    输出:按age排序输出,从小到大:
    [People(name=Daniel, age=10, sex=boy), 
    People(name=Lucy, age=10, sex=girl),
     People(name=Jack, age=20, sex=boy)]

Comparator.comparing(People::getAge)默认从小到大排序,

加上.reversed()就是倒序,从大到小:

复制代码
 @Test
    public void filter(){
        List<People> list = People.listDemoPeople();
        List<People> girls = list.stream()
                .sorted(Comparator.comparing(People::getAge).reversed())
                .limit(3)
                .toList();
        System.out.println(girls);
    }
    输出:
    [People(name=Tom, age=40, sex=boy), 
    People(name=Nancy, age=30, sex=girl), 
    People(name=Jack, age=20, sex=boy)]

5.map和flatmap

姓名"Jack","Daniel","Lucy","Tom","Nancy"

现在要实现所有姓名中每个不同的字母只出输出一次

复制代码
@Test
 public void flatmap(){
        List<People> list = People.listDemoPeople();
        List<String[]> strs= list.stream()
                .map(p->p.getName().split(""))
                .distinct()
                .toList();
        for(String[] s:strs){
            System.out.println(Arrays.toString(s));
        }
    }
    输出:
    [J, a, c, k]
    [D, a, n, i, e, l]
    [L, u, c, y]
    [T, o, m]
    [N, a, n, c, y]

.map(p->p.getName().split("")) 返回的是Stream(String[]), 就是{ [J, a, c, k], [D, a, n, i, e, l],[L, u, c, y], [T, o, m],[N, a, n, c, y]},一共5个姓名的数组。然后执行distinct()比较的是String[]数组,每个数组都不一样,所以输出全部数组。

我们想要的是5个姓名组成一个大的数组{ J, a, c, k, D, a, n, i, e, l,L, u, c, y, T, o, m,N, a, n, c, y},然后对这个数组执行distinct(),比较的就是每个字母,最终输出不同的字母。

可以用flatMap,代码如下:

可以看代码中map和flatMap后面的提示,map后流中是String数组(就是上面5个姓名的数组),flatMap后流中是一个个String(就是5个姓名所有的字符)

复制代码
 @Test
 public void flatmap(){
        List<People> list = People.listDemoPeople();
        List<String> strs = list.stream()
                .map(p->p.getName().split(""))
                .flatMap(s-> Arrays.stream(s))
                .distinct()
                .toList();
        System.out.println(strs);
    }
    输出是:
    [J, a, c, k, D, n, i, e, l, L, u, y, T, o, m, N]

6.查询匹配方法

allMatch、anyMatch、noneMatch、findFirst,findAny这些方法,看名称就知道意思了,就不一一介绍,以allMatch为例:查询所有人的age是否都小于100。

复制代码
 @Test
    public void allMatch(){
        List<People> list = People.listDemoPeople();
        boolean b = list.stream().allMatch(p-> p.getAge() < 100);
        System.out.println(b);
    }
    输出:
    true

7.reduce

reduce()有两种写法,

  • 一种有初始值,reduce(初始值,函数式接口)
  • 一种没有初始值,reduce(函数式接口)
    函数式接口要求是:传入两个同类型对象a和b,经过一系列计算,返回的一个对象(这个对象的数据类型要和a,b类型一样)
    reduce如果有初始值,初始值的类型也要和a,b类型一样。

简单来说,reduce就是把流中的数据进行两两计算。

下面用reduce这两种方法,实现求所有人的age和

写法1:.reduce(0,(a,b)->a+b);

reduce第一个参数是0,就是初始值,如果所有人的age都为null的话,和就是0

复制代码
@Test
    public void reduce(){
        List<People> list = People.listDemoPeople();
        Integer sum = list.stream().map(p->p.getAge())
                        .reduce(0,(a,b)->a+b);   //这里0,a,b ,a+b都是int,同一类型。
        System.out.println(sum);
    }
    输出:
    110

写法2:.reduce((a,b)->a+b);没有初始值,如果所有人的age都为null的话,就没有和,所以返回的是Optional<>

复制代码
 @Test
    public void reduce(){
        List<People> list = People.listDemoPeople();
        Optional<Integer> sum = list.stream().map(p->p.getAge())
                        .reduce((a,b)->a+b);
        System.out.println(sum.get());
    }
    输出:
    110

求最大age的人

复制代码
@Test
    public void reduce(){
        List<People> list = People.listDemoPeople();
        Optional<People> p = list.stream()
                        .reduce((a,b)-> {         //这里a,b,和下面return都是People类型
                          if(a.getAge() - b.getAge() > 0){
                              return a;
                          }else {
                              return b;
                          }
                        });
        System.out.println(p.get());
    }
    输出:
   People(name=Tom, age=40, sex=boy)

8.Collectors.groupingBy

把相同age的人放在一起

复制代码
@Test
    public void groupBy(){
        List<People> list = People.listDemoPeople();
        Map<Integer, List<People>> map = list.stream()
                        .collect(Collectors.groupingBy(People::getAge));
        System.out.println(map);
    }
    输出:
    {20=[People(name=Jack, age=20, sex=boy)],
     40=[People(name=Tom, age=40, sex=boy)],
     10=[People(name=Daniel, age=10, sex=boy), People(name=Lucy, age=10, sex=girl)],
     30=[People(name=Nancy, age=30, sex=girl)]}

9.Collectors.toMap

复制代码
 @Test
    public void toMap(){
        List<People> list = People.listDemoPeople();
        Map<Integer, People> map = list.stream()
                .collect(Collectors.toMap(People::getAge,p->p,(oldValue, newValue) -> newValue));
        System.out.println(map);
    }
    输出:
    {20=People(name=Jack, age=20, sex=boy), 
    40=People(name=Tom, age=40, sex=boy), 
    10=People(name=Lucy, age=10, sex=girl), 
    30=People(name=Nancy, age=30, sex=girl)}

Collectors.toMap(People::getAge,p->p,(oldValue, newValue) -> newValue),含义如下:

  • People::getAge,用age作为key
  • p->p, 用People作为value
  • (oldValue, newValue) -> newValue,如果key相同(有相同的age),value用新的people替换原来的people

如果我们确定所有人的age都不一样,不会有冲突可以这样写

Collectors.toMap(People::getAge,p->p)

10.Collectors.partitioningBy

按sex分区,两个key是true和false

复制代码
@Test
    public void partitioningBy(){
        List<People> list = People.listDemoPeople();
        Map<Boolean, List<People>> map = list.stream()
                .collect(Collectors.partitioningBy(p->p.getSex().equals("boy")));
        System.out.println(map);
    }
    输出:
    {false=[People(name=Lucy, age=10, sex=girl), People(name=Nancy, age=30, sex=girl)], 
    true=[People(name=Jack, age=20, sex=boy), People(name=Daniel, age=10, sex=boy), People(name=Tom, age=40, sex=boy)]}

求不同sex中age最大的人

复制代码
@Test
    public void partitioningBy(){
        List<People> list = People.listDemoPeople();
        Map<Boolean, People> map = list.stream()
                .collect(Collectors.partitioningBy(p->p.getSex().equals("boy"),
                        Collectors.collectingAndThen(
                                Collectors.maxBy((a,b)-> a.getAge()-b.getAge()),
                                 p-> p.get()))
                );
        System.out.println(map);
    }
    输出:
    {false=People(name=Nancy, age=30, sex=girl), 
     true=People(name=Tom, age=40, sex=boy)}
相关推荐
遥不可及~~斌26 分钟前
基于Redis实现短信防轰炸的Java解决方案
java·数据库·redis
AronTing1 小时前
300%性能提升!CompletableFuture异步编排四大核心模式与避坑指南
java·后端·安全
java奋斗者1 小时前
基于Java的人脸识别在线考试系统(jsp+springboot+mysql8.x)
java·开发语言·spring boot
Moso_Rx1 小时前
JavaEE——Thread类的基本用法
java·java-ee
魔道不误砍柴功1 小时前
Jakarta EE 11发布:云原生Java企业应用的新标准
java·开发语言·云原生
bug菌1 小时前
经理突然问我为什么BigDecimal可以不丢失精度?我表示...😨
java·后端·java ee
创码小奇客2 小时前
MongoDB:数据库界的 “狂野西部牛仔”
java·mongodb·trae
Spring-wind2 小时前
【golang】为什么协程开销小于线程
java·开发语言·golang
隔壁小查2 小时前
【后端开发】Spring MVC-常见使用、Cookie、Session
java·spring·mvc
呦呦鹿鸣Rzh3 小时前
SpringMVC的请求-文件上传
java·前端·html