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)}
相关推荐
小钊(求职中)17 分钟前
最新Git入门到精通完整教程
java·git·后端·spring·面试
三天不学习22 分钟前
23种设计模式之单例模式(Singleton Pattern)【设计模式】
java·单例模式·设计模式·c#
大彬聊编程23 分钟前
京东一面:为什么 IDEA 建议去掉 StringBuilder,而要使用 “+” 拼接字符串?
java
java技术小馆24 分钟前
IDEA 接入 Deepseek
java·ide·intellij-idea·ai编程
WangYaolove131426 分钟前
java2025热点面试题之springmvc
java·springmvc
程序视点34 分钟前
JVM虚拟机监控及性能调优实战
java·jvm·后端
橘猫云计算机设计1 小时前
基于微信小程序的疫情互助平台(源码+lw+部署文档+讲解),源码可白嫖!
java·大数据·开发语言·spring boot·微信小程序·小程序·汽车
m0_672449601 小时前
使用Java操作Excel
java·python·excel
customer081 小时前
【开源免费】基于SpringBoot+Vue.JS医院药品管理系统(JAVA毕业设计)
java·vue.js·spring boot·后端·开源
无世世2 小时前
【Java从入门到起飞】面向对象编程(基础)
java·开发语言