栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

stream流常用操作

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

操作:

public class StreamDemo2 {
    public static void main(String[] args) {
//        流的常用操作,筛选,匹配,遍历
        List 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 first = personList.stream().filter(p -> p.getAge() > 20).findFirst();
//        findAny 常和并行流一起搭配使用
        Optional 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 collect = personList.stream().filter(p -> p.getSalary() > 8000).collect(Collectors.toList());
//        筛选出来工资大于8000的小伙伴,并生成新名称的集合
        List 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 max = personList.stream().map(Person::getCountry).max(Comparator.comparing(String::length));
        System.out.println("人员居住地字符串长度最长的:"+max);

输出:

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

2)筛选出来年龄最小的

//        筛选出来年龄最小
        Optional min = personList.stream().map(Person::getAge).min(Integer::compareTo);
        System.out.println("年龄最小的人员:"+min);
//        也可以自定义比较规则,Comparator
        Optional min1 = personList.stream().map(Person::getAge).min(new Comparator() {
            @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映射

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

  • map:接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。
  • flatMap:接收一个函数作为参数,将流中的每个值都换成另一个流,然后把所有流连接成一个流。
//        所有员工工资加上1k 1、不改变原来的集合,2、改变原来集合
//        1、不改变原来的集合,
        List 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 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 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 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 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 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 collect4 = personList.stream().filter(p -> p.getSalary() > 8000).collect(Collectors.toList());
        System.out.println("工资大于8k的集合:"+JSONObject.toJSONString(collect4));
//        工资大于8k的人员姓名
        List collect5 = personList.stream().filter(p -> p.getSalary() > 8000).map(Person::getName).collect(Collectors.toList());
        System.out.println("工资大于8k的人员姓名:"+JSONObject.toJSONString(collect5));
//        工资大于8k的人员姓名 set
        Set collect6 = personList.stream().filter(p -> p.getSalary() > 8000).map(Person::getName).collect(Collectors.toSet());
        System.out.println("工资大于8k的人员姓名:"+JSONObject.toJSONString(collect6));
//        工资大于8k的人员姓名 map
        Map collect7 = personList.stream().filter(p -> p.getSalary() > 8000).collect(Collectors.toMap(Person::getName, Person::getSalary));
        System.out.println("工资大于8k的人员姓名map:"+JSONObject.toJSONString(collect7));

结果:

工资大于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

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/865067.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号