stream流常用操作

1、概述:

jdk8中出现了stream,lambda表达式等,对操作集合提供了很快捷的操作;

主要功能实现:将操作元素当成流来出来,然后调用stream API方法,对元素进行操作。

1)流的操作类型

流的操作类型分为两种:

  • Intermediate(中间的):一个流可以后面跟随零个或多个intermediate操作。其目的主要是打开流,做出某种程度的数据映射/过滤,然后返回一个新的流,交给下一个操作使用。这类操作都是惰性化的(lazy),就是说,仅仅调用到这类方法,并没有真正开始流的遍历。

  • Terminal(终端):一个流只能有一个terminal操作,当这个操作执行后,流就被使用“光”了,无法再被操作。所以,这必定是流的最后一个操作。Terminal操作的执行,才会真正开始流的遍历,并且会生成一个结果,或者一个side effect。

    在对一个Stream进行多次转换操作(Intermediate 操作),每次都对Stream的每个元素进行转换,而且是执行多次,这样时间复杂度就是N(转换次数)个for循环里把所有操作都做掉的总和吗?其实不是这样的,转换操作都是lazy的,多个转换操作只会在Terminal操作的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream里有个操作函数的集合,每次转换操作就是把转换函数放入这个集合中,在Terminal 操作的时候循环Stream对应的集合,然后对每个元素执行所有的函数。

    还有一种操作被称为short-circuiting。用以指:对于一个intermediate操作,如果它接受的是一个无限大(infinite/unbounded)的Stream,但返回一个有限的新Stream;对于一个terminal操作,如果它接受的是一个无限大的Stream,但能在有限的时间计算出结果。
    当操作一个无限大的 Stream,而又希望在有限时间内完成操作,则在管道内拥有一个short-circuiting操作是必要非充分条件。

2) 流的特性
  1. stream不存储数据,而是按照特定的规则对数据进行计算,一般会输出结果。
  2. stream不会改变数据源,通常情况下会产生一个新的集合或一个值。
  3. stream具有延迟执行特性,只有调用终端操作时,中间操作才会执行。
2、流的创建
1、流的创建

可以创建并行流和串行流

两者之间的区别详见:https://blog.csdn.net/weixin_43987718/article/details/124388021

并行流也可以通过:

集合创建流

        List<String> strList = Arrays.asList("a", "b", "c", "d");
//        串行流
        List<String> list = strList.stream().filter(x -> x.equals("a")).collect(Collectors.toList());
//        并行流创建的两种方式
        List<String> list2 = strList.parallelStream().filter(x -x.equals("a")).collect(Collectors.toList());
     List<String> list2 = strList.stream().parallel().filter(x -> x.equals("a")).collect(Collectors.toList());

也可以通过Arrays来创建

// 1. Individual values
Stream stream = Stream.of("a", "b", "c");

// 2. Arrays
String [] strArray = new String[] {"a", "b", "c"};
stream = Stream.of(strArray);
stream = Arrays.stream(strArray);

// 3. Collections
List<String> list = Arrays.asList(strArray);
stream = list.stream();1234567891011
2、流的常用方法
1、match、foreach、find使用

创建一个实体

@Data
public class Person {
    private String name;
    private String sex;
    private int age;
    private int salary;
    private String country;

    Person(String name ,String sex,int age,int salary,String country){
        this.salary = salary;
        this.name = name;
        this.sex = sex;
        this.age = age;
        this.country = country;
    }
}

操作:

/**
 * 描述
 *
 * @author LZH
 * @version 1.0
 * @date 2022/05/06 15:58:56
 */
public class StreamDemo2 {
    public static void main(String[] args) {
//        流的常用操作,筛选,匹配,遍历
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("小张","男",18,3200,"南京"));
        personList.add(new Person("小李","女",18,8200,"连云港"));
        personList.add(new Person("小王","女",22,10200,"徐州"));
        personList.add(new Person("小刘","男",24,8200,"苏州"));
        personList.add(new Person("小梁","女",26,5200,"上海"));
        personList.add(new Person("小六","男",19,9200,"无锡"));
//        遍历
        personList.stream().forEach(p->{
            System.out.println(p);
        });
//        筛选
//        筛选大于20岁的第一个
        Optional<Person> first = personList.stream().filter(p -> p.getAge() > 20).findFirst();
//        findAny 常和并行流一起搭配使用
        Optional<Person> firs2 = personList.stream().parallel().filter(p -> p.getAge() > 20).findAny();
//        是否存在大于20岁的
        boolean b = personList.stream().anyMatch(p -> p.getAge() > 20);

        System.out.println("筛选大于20岁的第一个"+ JSONObject.toJSONString(first));
        System.out.println("筛选大于20岁的任意一个"+ JSONObject.toJSONString(firs2));
        System.out.println("是否存在大于20岁的"+ b);
    }
}

结果:

Person(name=小张, sex=, age=18, salary=3200, country=南京)
Person(name=小李, sex=, age=18, salary=8200, country=连云港)
Person(name=小王, sex=, age=22, salary=10200, country=徐州)
Person(name=小刘, sex=, age=24, salary=8200, country=苏州)
Person(name=小梁, sex=, age=26, salary=5200, country=上海)
Person(name=小六, sex=, age=19, salary=9200, country=无锡)
筛选大于20岁的第一个{"age":22,"country":"徐州","name":"小王","salary":10200,"sex":"女"}
筛选大于20岁的任意一个{"age":24,"country":"苏州","name":"小刘","salary":8200,"sex":"男"}
是否存在大于20岁的true
2、筛选 filter

筛选出来工资大于8000的小伙伴,并生成新的集合

//        筛选出来工资大于8000的小伙伴,并生成新的集合
        List<Person> collect = personList.stream().filter(p -> p.getSalary() > 8000).collect(Collectors.toList());
//        筛选出来工资大于8000的小伙伴,并生成新名称的集合
        List<String> collect1 = personList.stream().filter(p -> p.getSalary() > 8000).map(Person::getName).collect(Collectors.toList());
        System.out.println("筛选出来工资大于8000的小伙伴"+ JSONObject.toJSONString(collect));
        System.out.println("筛选出来工资大于8000的小伙伴的名称"+ JSONObject.toJSONString(collect1));

结果:

筛选出来工资大于8000的小伙伴[{"age":18,"country":"连云港","name":"小李","salary":8200,"sex":"女"},{"age":22,"country":"徐州","name":"小王","salary":10200,"sex":"女"},{"age":24,"country":"苏州","name":"小刘","salary":8200,"sex":"男"},{"age":19,"country":"无锡","name":"小六","salary":9200,"sex":"男"}]
筛选出来工资大于8000的小伙伴的名称["小李","小王","小刘","小六"]

3、max、min、count

1)获取居住地名称最长的

//        获取家乡名称最长的
        Optional<String> max = personList.stream().map(Person::getCountry).max(Comparator.comparing(String::length));
        System.out.println("人员居住地字符串长度最长的:"+max);

输出:

人员居住地字符串长度最长的:Optional[连云港]

2)筛选出来年龄最小的

//        筛选出来年龄最小
        Optional<Integer> min = personList.stream().map(Person::getAge).min(Integer::compareTo);
        System.out.println("年龄最小的人员:"+min);
//        也可以自定义比较规则,Comparator
        Optional<Integer> min1 = personList.stream().map(Person::getAge).min(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1.compareTo(o2);
            }
        });
        System.out.println("年龄最小的人员:"+min1);

输出:

年龄最小的人员:Optional[18]
年龄最小的人员:Optional[18]

3)获取工资大于8k的人员个数

//        获取工资大于8k的个数
        long count = personList.stream().map(Person::getSalary).filter(p -> p > 8000).count();
        System.out.println("获取工资大于8k的个数"+count);

输出:

获取工资大于8k的个数4
4、map和flatMap映射

映射,可以将一个流的元素按照一定的映射规则映射到另一个流中。分为mapflatMap

  • map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
  • flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
//        所有员工工资加上1k 1、不改变原来的集合,2、改变原来集合
//        1、不改变原来的集合,
        List<Person> collect2 = personList.stream().map(person -> {
            Person person1 = new Person(person.getName(), person.getSex(), person.getAge(), person.getSalary() + 1000, person.getCountry());
            return person1;
        }).collect(Collectors.toList());
        System.out.println("1、不改变原来的集合,"+JSONObject.toJSONString(collect2));
//     改变原来集合
        List<Person> collect3 = personList.stream().map(person -> {
            person.setSalary(person.getSalary() + 1000);
            return person;
        }).collect(Collectors.toList());
        System.out.println("2、改变原来集合"+collect3);

输出:

1、不改变原来的集合,[{"age":18,"country":"南京","name":"小张","salary":4200,"sex":"男"},{"age":18,"country":"连云港","name":"小李","salary":9200,"sex":"女"},{"age":22,"country":"徐州","name":"小王","salary":11200,"sex":"女"},{"age":24,"country":"苏州","name":"小刘","salary":9200,"sex":"男"},{"age":26,"country":"上海","name":"小梁","salary":6200,"sex":"女"},{"age":19,"country":"无锡","name":"小六","salary":10200,"sex":"男"}]
2、改变原来集合[Person(name=小张, sex=, age=18, salary=4200, country=南京), Person(name=小李, sex=, age=18, salary=9200, country=连云港), Person(name=小王, sex=, age=22, salary=11200, country=徐州), Person(name=小刘, sex=, age=24, salary=9200, country=苏州), Person(name=小梁, sex=, age=26, salary=6200, country=上海), Person(name=小六, sex=, age=19, salary=10200, country=无锡)]
Disconnected from the target VM, address: '127.0.0.1:8836', transport: 'socket'
5、reduce(归约)

归约,也称缩减,顾名思义,是把一个流缩减成一个值,能实现对集合求和、求乘积和求最值操作。

//        reduce 归约
//        求和
        Optional<Integer> reduce = personList.stream().map(Person::getSalary).reduce(Integer::sum);
        System.out.println("求和:"+reduce.get());
//        求和方式2
        int sum = personList.stream().mapToInt(Person::getSalary).sum();
        System.out.println("求和2:"+sum);
//        求和方式3
        Optional<Integer> reduce3 = personList.stream().map(Person::getSalary).reduce((x, y) -> x + y);
        System.out.println("求和3:"+reduce3.get());
//        求和方式4
        Integer reduce1 = personList.stream().map(Person::getSalary).reduce(1, Integer::sum);
        System.out.println("求和4:"+reduce3.get());
//        求最大值
        Optional<Integer> reduce2 = personList.stream().map(Person::getSalary).reduce((x, y) -> x > y ? x : y);
        System.out.println("求最大值:"+reduce2.get());
//        求最大值
        Integer reduce4 = personList.stream().map(Person::getSalary).reduce(1, Integer::max);
        System.out.println("求最大值:"+reduce4);
//        求乘积
        Optional<Integer> reduce5 = personList.stream().map(Person::getSalary).reduce((x, y) -> x * y);
        System.out.println("求乘积:"+reduce5.get());
        int i = 1;
        for (Person person : personList){
            i = i * person.getSalary();
        }
        System.out.println("求乘积:"+i);

输出结果:

求和:50200
求和2:50200
求和3:50200
求和4:50200
求最大值:11200
求最大值:11200
求乘积:-1149239296
求乘积:-1149239296
6、collect(收集)

流最终的操作还是要把处理过的数据给收集起来,可能是原来的集合,也可能是一个新的集合

6.1、toList,toMap,toSet
//        collect收集
//        常用的toList,toMap,toSet等
//        工资大于8k的集合
        List<Person> collect4 = personList.stream().filter(p -> p.getSalary() > 8000).collect(Collectors.toList());
        System.out.println("工资大于8k的集合:"+JSONObject.toJSONString(collect4));
//        工资大于8k的人员姓名
        List<String> collect5 = personList.stream().filter(p -> p.getSalary() > 8000).map(Person::getName).collect(Collectors.toList());
        System.out.println("工资大于8k的人员姓名:"+JSONObject.toJSONString(collect5));
//        工资大于8k的人员姓名 set
        Set<String> collect6 = personList.stream().filter(p -> p.getSalary() > 8000).map(Person::getName).collect(Collectors.toSet());
        System.out.println("工资大于8k的人员姓名:"+JSONObject.toJSONString(collect6));
//        工资大于8k的人员姓名 map
        Map<String, Integer> collect7 = personList.stream().filter(p -> p.getSalary() > 8000).collect(Collectors.toMap(Person::getName, Person::getSalary));
        System.out.println("工资大于8k的人员姓名map:"+JSONObject.toJSONString(collect7));

根据指定字段去重
保留第一条记录

ArrayList<Person> collect = list.stream().collect(
                Collectors.collectingAndThen(
                        Collectors.toCollection(
                                () -> new TreeSet<>(
                                        Comparator.comparing(tc -> tc.getSalary())
                                )
                        ), ArrayList::new
                )
        );

保留最后一条记录,使用map

        List<Person> collect = list.stream().collect(
                Collectors.toMap(Person::getSalary, Function.identity(), (a1, a2) -> a2, LinkedHashMap::new)
        ).values().stream().collect(Collectors.toList());

结果:

工资大于8k的集合:[{"age":18,"country":"连云港","name":"小李","salary":9200,"sex":"女"},{"age":22,"country":"徐州","name":"小王","salary":11200,"sex":"女"},{"age":24,"country":"苏州","name":"小刘","salary":9200,"sex":"男"},{"age":19,"country":"无锡","name":"小六","salary":10200,"sex":"男"}]
工资大于8k的人员姓名:["小李","小王","小刘","小六"]
工资大于8k的人员姓名:["小刘","小李","小六","小王"]
工资大于8k的人员姓名map:{"小刘":9200,"小李":9200,"小六":10200,"小王":11200}
6.2 统计 count/average
//        常用的一些静态统计方法  count/average
//        Collectors 用于统计的一系列静态方法
//        计数:count
//        平均值:averagingInt、averagingLong、averagingDouble
//        最值:maxBy、minBy
//        求和:summingInt、summingLong、summingDouble
//        统计以上所有:summarizingInt、summarizingLong、summarizingDouble
        Long collect8 = personList.stream().collect(Collectors.counting());
        System.out.println("人员数量:"+collect8);
//        统计工资平均值
        Double collect9 = personList.stream().collect(Collectors.averagingInt(Person::getSalary));
        System.out.println("工资平均值:"+collect9);
//        统计工资最大值
        Optional<Integer> collect10 = personList.stream().map(Person::getSalary).collect(Collectors.maxBy(Integer::compareTo));
        System.out.println("工资最大值:"+collect10.get());
//        工资求和
        Integer collect11 = personList.stream().collect(Collectors.summingInt(Person::getSalary));
        System.out.println("工资求和:"+collect11);
//        统计以上所有
        IntSummaryStatistics collect12 = personList.stream().collect(Collectors.summarizingInt(Person::getSalary));
        System.out.println("统计所有:"+collect12);

结果:

人员数量:6
工资平均值:8366.666666666666
工资最大值:11200
工资求和:50200
统计所有:IntSummaryStatistics{count=6, sum=50200, min=4200, average=8366.666667, max=11200}
6.3 分组(partitioningBy/groupingBy)

partitioningBy:只能分为两组,且key是boolean型

groupingBy:没有限制,key是string

//        分组(partitioningBy/groupingBy)
        Map<Boolean, List<Person>> collect13 = personList.stream().collect(Collectors.partitioningBy(p -> p.getSalary() > 8000));
        System.out.println("boolean分组数据:"+JSONObject.toJSONString(collect13));
//        按照性别分组
        Map<String, List<Person>> collect14 = personList.stream().collect(Collectors.groupingBy(Person::getSex));
        System.out.println("性别分组:"+JSONObject.toJSONString(collect14));
//        按照性别分组,在按照地区分组
        Map<String, Map<String, List<Person>>> collect15 = personList.stream().collect(Collectors.groupingBy(Person::getSex, Collectors.groupingBy(Person::getCountry)));
        System.out.println("性别分组、地区分组:"+JSONObject.toJSONString(collect15));

结果:

boolean分组数据:{
    false:[{"age":18,"country":"南京","name":"小张","salary":4200,"sex":"男"},{"age":26,"country":"上海","name":"小梁","salary":6200,"sex":"女"}],
    true:[{"age":18,"country":"连云港","name":"小李","salary":9200,"sex":"女"},{"age":22,"country":"徐州","name":"小王","salary":11200,"sex":"女"},{"age":24,"country":"苏州","name":"小刘","salary":9200,"sex":"男"},{"age":19,"country":"无锡","name":"小六","salary":10200,"sex":"男"}]}
性别分组:{"女":[{"age":18,"country":"连云港","name":"小李","salary":9200,"sex":"女"},{"age":22,"country":"徐州","name":"小王","salary":11200,"sex":"女"},{"age":26,"country":"上海","name":"小梁","salary":6200,"sex":"女"}],"男":[{"age":18,"country":"南京","name":"小张","salary":4200,"sex":"男"},{"age":24,"country":"苏州","name":"小刘","salary":9200,"sex":"男"},{"age":19,"country":"无锡","name":"小六","salary":10200,"sex":"男"}]}
性别分组、地区分组:{"女":{"上海":[{"age":26,"country":"上海","name":"小梁","salary":6200,"sex":"女"}],"徐州":[{"age":22,"country":"徐州","name":"小王","salary":11200,"sex":"女"}],"连云港":[{"age":18,"country":"连云港","name":"小李","salary":9200,"sex":"女"}]},"男":{"无锡":[{"age":19,"country":"无锡","name":"小六","salary":10200,"sex":"男"}],"苏州":[{"age":24,"country":"苏州","name":"小刘","salary":9200,"sex":"男"}],"南京":[{"age":18,"country":"南京","name":"小张","salary":4200,"sex":"男"}]}}
Disconnected from the target VM, address: '127.0.0.1:3685', transport: 'socket'
6.4 joining 连接
//        join 连接
        String collect16 = personList.stream().map(Person::getName).collect(Collectors.joining(","));
        System.out.println("join连接:"+collect16);

结果:

join连接:小张,小李,小王,小刘,小梁,小六
7、排序 sorted
package com.example.Stream;

import com.alibaba.fastjson.JSONObject;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 描述
 *
 * @author LZH
 * @version 1.0
 * @date 2022/05/13 13:25:05
 */
public class StreamDemo3 {
    public static void main(String[] args) {
        List<Person> personList = new ArrayList<>();
        personList.add(new Person("小张","男",18,3200,"南京"));
        personList.add(new Person("小李","女",18,8200,"连云港"));
        personList.add(new Person("小王","女",22,10200,"徐州"));
        personList.add(new Person("小刘","男",24,8200,"苏州"));
        personList.add(new Person("小梁","女",26,5200,"上海"));
        personList.add(new Person("小六","男",19,9200,"无锡"));

//        排序 sorted  调用Compator方法,或者自定义方法
//        自认排序升序
        List<String> collect = personList.stream().sorted(Comparator.comparing(Person::getSalary)).map(Person::getName).collect(Collectors.toList());
        System.out.println("升序:"+ JSONObject.toJSONString(collect));
//        降序排序  reversed 降序
        List<String> collect1 = personList.stream().sorted(Comparator.comparing(Person::getSalary).reversed()).map(Person::getName).collect(Collectors.toList());
        System.out.println("降序:"+JSONObject.toJSONString(collect1));
//        按照工资排序,工资一样的话,按照年龄排序
        List<String> collect2 = personList.stream().sorted(Comparator.comparing(Person::getSalary).thenComparing(Person::getAge)).map(Person::getName).collect(Collectors.toList());
        System.out.println(" 按照工资排序,工资一样的话,按照年龄排序:"+collect2);
//        自定义排序
        List<String> collect3 = personList.stream().sorted((p1,p2)->{
            if (p1.getSalary() == p2.getSalary()){
                return p1.getAge() - p2.getAge();
            }else {
                return p1.getSalary() - p2.getSalary();
            }
        }).map(Person::getName).collect(Collectors.toList());
        System.out.println("自定义排序:"+collect3);

    }
}

自定义的排序的return 语句 ==> 三元运算符

结果:

升序:["小张","小梁","小李","小刘","小六","小王"]
降序:["小王","小六","小李","小刘","小梁","小张"]
 按照工资排序,工资一样的话,按照年龄排序:[小张, 小梁, 小李, 小刘, 小六, 小王]
自定义排序:[小张, 小梁, 小李, 小刘, 小六, 小王]
8、去重distinct,跳过skip,限制
package com.example.Stream;

import com.alibaba.fastjson.JSONObject;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 描述
 *
 * @author LZH
 * @version 1.0
 * @date 2022/05/13 13:25:05
 */
public class StreamDemo4 {
    public static void main(String[] args) {
        String [] arr1 = {"a","b","c","d"};
        String [] arr2 = {"a","b","c","e"};
//        流的去重distinct,跳过skip,限制
//        流的合并
        Stream<String> stream1 = Stream.of(arr1);
        Stream<String> stream2 = Stream.of(arr2);

        List<String> collect = Stream.concat(stream2, stream1).collect(Collectors.toList());
        System.out.println("流的合并:"+JSONObject.toJSONString(collect));
//        去重
        List<String> collect1 = collect.stream().distinct().collect(Collectors.toList());
        System.out.println("去重:"+JSONObject.toJSONString(collect1));
//        限制 整数,从1开始,每隔4个取一值,取前10个
        List<Integer> collect2 = Stream.iterate(1, x -> x + 4).limit(10).collect(Collectors.toList());
        System.out.println("限制:"+JSONObject.toJSONString(collect2));

//        跳过 跳过的位数
        List<Integer> collect3 = Stream.iterate(1, x -> x + 4).skip(5).limit(5).collect(Collectors.toList());
        System.out.println("跳过:"+JSONObject.toJSONString(collect3));


    }
}

结果:

流的合并:["a","b","c","e","a","b","c","d"]
去重:["a","b","c","e","d"]
限制:[1,5,9,13,17,21,25,29,33,37]
跳过:[21,25,29,33,37]

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值