java8 的stream流

目录

一、stream流的分类

二、stream流的用法 

1、准备工作

2.流的构造

3.方法测试 (测试方法的用法)

1.filter方法

2.map

3.flatMap

4.distinct() 

5.sorted()

6.peek()

 7.limit()

8.skip()

9.foreach()

10.forEachOrdered()

11.toArray()

12.reduce()

13.collect()

14.anyMatch()、allMatch()、noneMatch()

15.findFirst()、findAny()

16.stream流的一些操作(待考证)

三、Optional类


一、stream流的分类

分为串行流和并行流。

使用parallelStream方法可以得到一个并行流,并行流底层使用的是forkjoin框架,对于一些计算量比较大的任务,使用并行流可能极大的提升效率。但是使用并行流必须保证每个元素都独立不受影响。每一个元素的功能(function)在做什么及它是否适合运行在并行代码中。当方法是调用一些同步方法,并行流可能会在同步方法上等待,进而导致并行流的性能并没有想象中高。(所以要有选择的使用)。

串行流就是按照顺序执行的,平常最多使用的就是这个。

其中Stream有一个源,0个或者多个中间操作,以及一个终止操作。Stream只有遇到终止操作,它的源才开始执行遍历操作,而且只会进行一次遍历,而不是每个操作都执行一次遍历。

java中的Stream带有lazy执行特征,在整个操作过程中, 只有遇到terminate操作函数,才会触发stream的整体运算。即,如果没有terminate动作,中间不论做什么, 都不会执行。map和peek都属于中间操作,只有执行完终止操作才会对原来的对象进行改变。

常见的操作可以归类如下:

  • Intermediate 操作(中间操作)

  • Terminal 操作(终止操作)

  • Short-circuiting 操作(短路操作)当操作一个无限大的Stream,而又希望在有限时间内完成操作,则在管道内拥有一个 short-circuiting 操作是必要非充分条件。

借鉴stream的分类(上图借鉴的连接,支持原创)

其中limit是一个 short-circuiting stateful intermediate operation (也是一个短路操作)。

这样理解中间操作和终止操作。一个中间操作或者多个中间操作,其返回的结果对象还是一个stream流,但是一旦使用了终止操作,那么返回的就不在是一个stream流,就会返回对应的终止操作的对象。其中属于终止操作的短路操作也是会返回对应的对象,而不是一个流。

二、stream流的用法 

1、准备工作

(1)实体类 Admin 

/**
 * <p>
 * 管理员信息表
 * </p>
 *
 * @author zwh
 * @since 2021-09-01
 */
@Data
@EqualsAndHashCode(callSuper = false)
@TableName("lib_admin")
public class Admin implements Serializable {


    /**
     * 管理员id
     */
    @TableId(type = IdType.AUTO)
    private Long id;

    /**
     * 姓名
     */
    private String name;

    /**
     * 密码
     */
    private String password;

    /**
     * 加密盐
     */
    private String salt;

    /**
     * 创建时间
     */
    private LocalDateTime createTime;

    /**
     * 更新时间
     */
    private LocalDateTime updateTime;

    /**
     * 是否删除  0 否 false ,1 是 true
     */
    private Boolean isDeleted;


}

(2)数据库测试的数据

 以上面的数据为基准去测试对应的stream的方法。

2.流的构造

一般有三个方法。

1.直接赋值

2.数组构造

3.集合构造

// 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();

3.方法测试 (测试方法的用法)

(List<Admin> adminList = this.baseMapper.selectList(null)):默认的adminList为全查表数据

通过stream借助lamda表达式对集合collection进行操作(筛选、排序、聚合等),这里采用集合的方法去构造stream流

1.filter方法

filter方法是过滤方法,是留下符合条件的数据,形成一个新的stream流。

查出所有被删除的人。


    @Override
    public List<Admin> init() {
        /*
         学习stream流的用法
         */
        List<Admin> adminList = this.baseMapper.selectList(null);
        List<Admin> list = adminList.stream().filter(Admin::getIsDeleted).collect(Collectors.toList());

        return list ;
         //return this.baseMapper.selectList(Wrappers.<Admin>lambdaQuery().eq(Admin::getIsDeleted,true));


    }

上面可以看出filter的用法是留下符合filter(),括号里面的条件的数据,这里就是符合isdeletde = true ;把符合条件的保存下来,不符合条件的直接过滤。

当然也可以直接用一条sql查询,但是这里是测试filter的用法。

当然filter是一个中间操作,可以继续连接中间操作,知道遇到一个终止操作,这个stream流就停止了。

2.map

Returns a stream consisting of the results of applying the given function to the elements of this stream.

返回一个被函数处理后的流。接收一个函数作为参数,该函数会被应用到每个元素上,并将其映射成一个新的元素。

使用map()的重要特性就是在()里面设计函数,处理数据。相当于一个迭代器,迭代的处理每一个数据。

        List<Admin> list = adminList.stream().filter(Admin::getIsDeleted).collect(Collectors.toList());
        List<Boolean> boleanList = list.stream().map(Admin::getIsDeleted).collect(Collectors.toList());

看到map()和filter()的区别了吗?

同样的操作,filter()返回的是对象,而map()返回的仅仅只是admin的一个字段。

如果想要得到对应filter()一样的数据,返回的就是对应的对象。就是自己筛选符合条件的对象,并把符合条件的对象给返回给stream流,从而形成一个新的stream

        List<Admin> list1 = list.stream().map(i -> {
            if (i.getIsDeleted()) {
                return i;
            } else {
                return null;
            }
        }).collect(Collectors.toList());
 或者这么写 List<Admin> list1 = list.stream().map(i -> i.getIsDeleted() ? i : null).collect(Collectors.toList());

注意,map()的i代表的事list的每一个元素。

这其中map()可以干很多事情,毕竟是一个新的迭代器,基本上好多业务都是用map去完成的。

为了提高处理效率,官方已封装好了,三种变形:mapToDouble,mapToInt,mapToLong。其实很好理解,如果想将原Stream中的数据类型,转换为double,int或者是long是可以调用相对应的方法。

这三个方法是取出 Admin对象中对应类型的数据,然后形成一个新的流,对于这个流可以进行一些sum(),count(),average()。。。。。等等操作。

比如说

long count1 = adminList.stream().mapToLong(Admin::getId).sum();

这就是取出id字段,然后出所有id的和。

当然也可以把数据取出来作为数组。

        long[] array = adminList.stream().mapToLong(Admin::getId).toArray();
        for (Long count1:array) {
            System.out.println(count1);
        }

但是这个不如直接

List<Long> collect = adminList.stream().map(Admin::getId).collect(Collectors.toList());

所以这三个方法一般都是取出对应的数据进行求和,求平均数等等,一般是数据处理。

        long sum = adminList.stream().mapToLong(Admin::getId).sum();
        long count = adminList.stream().mapToLong(Admin::getId).count();
        OptionalDouble average = adminList.stream().mapToLong(Admin::getId).average();
        OptionalLong min = adminList.stream().mapToLong(Admin::getId).min();
        OptionalLong max = adminList.stream().mapToLong(Admin::getId).max();
        System.out.println("求和"+":  "+sum);
        System.out.println("求数量"+":  "+count);
        System.out.println("求平均数"+":  "+average);
        System.out.println("最小"+":  "+min);
        System.out.println("最大"+":  "+max);

结果

这其中后面三个max(),min(),average() 是Optional 对象,(这个也是java8的新的特性,是显式声明nullexcpetion异常,后面再详细写)

一般改为这样就会变成正常的取值了

System.out.println("求平均数"+":  "+average.getAsDouble());
System.out.println("最小"+":  "+min.getAsLong());
System.out.println("最大"+":  "+max.getAsLong());

Optional对象一般用ispresent()判断之后再用get进行取值。

3.flatMap

借鉴对flatMap的jieshao (下图借鉴的连接,支持原创)

 flatMap常用作对字符的处理。

同理还有flatMapToInt、flatMapToLong、flatMapToDouble 都类似map的对应的类型。当然要清楚flatMap和map的区别。

4.distinct() 

去重,因为list数组是有序可重复的数组,set是无序不可重复的数组。

是一个 stateful intermediate operation ,是一个中间操作,对数据进行去重处理。

首先给数据库加几个重复的名字

因为distinct()没有参数,默认是对对象的所有字段进行去重。

        List<String> list = adminList.stream().map(Admin::getName).distinct().collect(toList());
        list.forEach(System.out::println);

 

 由此可见确实去重了。

5.sorted()

排序,有两个方法,一个是有参数的,一个是没参数的。

1、sorted() 默认使用自然序排序, 其中的元素必须实现Comparable 接口
2、sorted(Comparator<? super T> comparator) :我们可以使用lambada 来创建一个Comparator 实例。可以按照升序或着降序来排序元素。

        System.out.println("========================降序");
        List<Admin> adminList = this.baseMapper.selectList(null);
        adminList.stream().sorted(Comparator.comparing(Admin::getId).reversed()).forEach(System.out::println);
        System.out.println("=============   升序");

        adminList.stream().sorted(Comparator.comparing(Admin::getId)).forEach(System.out::println);
        System.out.println("============= 升序");
        adminList.stream().sorted(new Comparator<Admin>() {
            @Override
            public int compare( Admin o1, Admin o2) {
                return o1.getId().compareTo(o2.getId());
            }
        }).forEach(System.out::println);

上面就是 对应按照某个字段进行升序和降序

6.peek()

如同于map,能得到流中的每一个元素。但map接收的是一个Function表达式,有返回值;而peek接收的是Consumer表达式,没有返回值。

        List<Admin> collect = adminList.stream().peek(o ->{
            if(o.getIsDeleted()){
                o.setName("测试测试");
            }else{
                o.setName("哦豁");
            }
        } ).collect(toList());

和map不同不需要返回值return,其余和map差不多。

但是官方文档写的,这个方法用于调试。。。。嗯。。嗯。。尽量不要用把。

This method exists mainly to support debugging, where you want to see the elements as they flow past a certain point in a pipeline

 7.limit()

如同单词意思,限制,截取

  List<Admin> collect = adminList.stream().limit(1).collect(toList());

取出集合的第一个元素。

8.skip()

和单词的意思一样,跳过。跳过指定数字的数据,留下剩下的数据。

List<Admin> collect1 = adminList.stream().skip(12).collect(toList());

 

9.foreach()

就是循环遍历和普通的foreach用法一样。是一个终止操作

adminList.stream().limit(2).forEach(System.out::println);

10.forEachOrdered()

顺序执行,严格按照顺序执行

而forerach是并行执行,不一定按照顺序打印出来,但是效率快

        System.out.println("==================================================");
        adminList.stream().limit(4).parallel().forEach(System.out::println);
        System.out.println("=====================这里是分割线=========================");
        adminList.stream().limit(4).parallel().forEachOrdered(System.out::println);

 如果不使用parallel()的话,两个一样都会按照顺序执行。所以一般都是直接使用foreach

11.toArray()

返回一个object类的数组,所以也可以直接把对象作为数组

    Object[] array = adminList.stream().map(Admin::getId).toArray();
     //Object[] objects = adminList.stream().toArray();

12.reduce()

累计(较为复杂),这里是其他人怎么写的,参考一下

这里是链接(借鉴的连接,支持原创)可以自己搜一下具体是怎么实现的。

13.collect()

可以收集流中的数据到【集合】或者【数组】中去。

常见的toList()

这里是链接 (借鉴的连接,支持原创)

一般这种复杂的分组求和等等操作都是在数据库就分好的,除非有特殊需求。

一些分组,分区等操作一般返回的就是map,map用的比较少,一般用的就是list

        Map<Boolean, List<Admin>> collect2 = adminList.stream().collect(Collectors.partitioningBy(Admin::getIsDeleted));

按照是否删除进行分区。(这个真不错)

{
    "code": 200,
    "message": "操作成功",
    "data": {
        "false": [
            {
                "id": 1,
                "name": "超级管理员",
                "password": "de760f9ca0761a2ac076698791498dc7",
                "salt": "lib0",
                "createTime": "2021-09-01T11:50:26",
                "updateTime": "2021-09-01T11:50:26",
                "isDeleted": false
            },
            {
                "id": 2,
                "name": "赵云",
                "password": "aff82c1e6486ac0fc9f2128991e9bf87",
                "salt": "lroT",
                "createTime": "2021-09-01T14:48:25",
                "updateTime": "2021-09-01T14:48:25",
                "isDeleted": false
            },
            {
                "id": 4,
                "name": "诸葛亮",
                "password": "f0b87c5a974f255954ea6b6ad1ed4400",
                "salt": "Gz1W",
                "createTime": "2021-09-01T15:00:18",
                "updateTime": "2021-09-01T15:00:18",
                "isDeleted": false
            },
            {
                "id": 5,
                "name": "关羽",
                "password": "c301e64419486a2f05e927a23a69b1d4",
                "salt": "Cmn7",
                "createTime": "2021-09-13T14:21:41",
                "updateTime": "2021-09-13T14:21:41",
                "isDeleted": false
            },
            {
                "id": 6,
                "name": "刘备",
                "password": "33addba7c0fa9f1a4e1665f14d6ec5b9",
                "salt": "rlTD",
                "createTime": "2021-10-18T14:04:42",
                "updateTime": "2021-10-18T14:04:42",
                "isDeleted": false
            },
            {
                "id": 8,
                "name": "上官婉儿",
                "password": "bb29c7caa87cd6936a1e995dd54307bc",
                "salt": "Zm54",
                "createTime": "2021-10-18T14:05:23",
                "updateTime": "2021-10-18T14:05:23",
                "isDeleted": false
            },
            {
                "id": 9,
                "name": "克莱汤普森",
                "password": "47ae31b05ec8e0248116c903fbf71af0",
                "salt": "761X",
                "createTime": "2021-10-18T14:05:38",
                "updateTime": "2021-10-18T14:05:38",
                "isDeleted": false
            },
            {
                "id": 1634546611531,
                "name": "库里",
                "password": "098672477bc4429a03796ec533a36c02",
                "salt": "GkP5",
                "createTime": "2021-10-18T16:43:32",
                "updateTime": "2021-10-18T16:43:32",
                "isDeleted": false
            },
            {
                "id": 1634547212517,
                "name": "库里",
                "password": "f55b377b4e4d1c8b10ca4f52921698ed",
                "salt": "SvZW",
                "createTime": "2021-10-18T16:53:33",
                "updateTime": "2021-10-18T16:53:33",
                "isDeleted": false
            },
            {
                "id": 1634547214180,
                "name": "库里",
                "password": "bae8b41d9464d610d99da3aca0a491ca",
                "salt": "Rg0Z",
                "createTime": "2021-10-18T16:53:34",
                "updateTime": "2021-10-18T16:53:34",
                "isDeleted": false
            },
            {
                "id": 1634547218177,
                "name": "库里",
                "password": "8f9b76f6b201ccd98bfff6796f70c772",
                "salt": "4HVT",
                "createTime": "2021-10-18T16:53:38",
                "updateTime": "2021-10-18T16:53:38",
                "isDeleted": false
            }
        ],
        "true": [
            {
                "id": 3,
                "name": "张飞",
                "password": "3979872148dabd65d33bb05edcbd2bf9",
                "salt": "3M97",
                "createTime": "2021-09-01T14:50:41",
                "updateTime": "2021-09-01T14:50:41",
                "isDeleted": true
            },
            {
                "id": 7,
                "name": "曹操",
                "password": "825d128d9e7ff2fca7eb0992ef14f520",
                "salt": "E5k4",
                "createTime": "2021-10-18T14:04:59",
                "updateTime": "2021-10-18T14:04:59",
                "isDeleted": true
            },
            {
                "id": 10,
                "name": "库里",
                "password": "533bf258d19ed412f3a55714394d87db",
                "salt": "4SC9",
                "createTime": "2021-10-18T14:05:49",
                "updateTime": "2021-10-18T14:05:49",
                "isDeleted": true
            }
        ]
    }
}

 Collectors.joining() 会根据指定的连接符,将所有元素连接成一个字符串。

//无参数--等价于 joining("");
joining()
//一个参数
joining(CharSequence delimiter)
//三个参数(中间连接+前缀+后缀)
joining(CharSequence delimiter, CharSequence prefix,CharSequence suffix)

        String collect3 = adminList.stream().map(Admin::getName).collect(joining());
        System.out.println(collect3);
        System.out.println("=====================这里是分割线=========================");
        System.out.println(adminList.stream().map(Admin::getName).collect(Collectors.joining(",")));
        System.out.println("=====================这里是分割线=========================");
        System.out.println(adminList.stream().map(Admin::getName).collect(Collectors.joining(",","-_-","^__^")));

14.anyMatch()、allMatch()、noneMatch()

anyMatch(Predicate p) 传入一个断言型函数,对流中所有的元素进行判断,只要有一个满足条件就返回true,都不满足返回false。

allMatch(Predicate p) 传入一个断言型函数, 对流中所有的元素进行判断,如果都满足返回true,否则返回false。

nonematch(Predicate p)传入一个断言型函数, 对流中所有的元素进行判断,全都不满足才会返回true。

15.findFirst()、findAny()

findFirst() 寻找第一个数据

findAny() 找到数据返回

findAny()操作,返回的元素是不确定的,对于同一个列表多次调用findAny()有可能会返回不同的值。使用findAny()是为了更高效的性能。如果是数据较少,串行地情况下,一般会返回第一个结果,如果是并行的情况,那就不能确保是第一个。

两个都是终止操作。

16.stream流的一些操作(待考证)

concat 连接两个流 ,of创建流数据,
empty创建一个有序的空的stream流,
generate 生成无限制的流

三、Optional类

见下一篇文章

可以参考这边文章

这是链接 (支持原创)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值