00:01
Hello,大家好,我是小石,嗯,今天呢,给大家分享一个这个STEM的使用,Stream在Java吧中还是经常用的吧,但是因为很多文章对这个stream介绍的不系统,只是介绍几个DEMO吧,所以我今天想系统的介绍一下这个STEM的使用。在介绍STEM之前呢,我们先来了解一下这个函数式接口,函数式接口的话,对是Java新提供的新特性啊。很多还有option类,或者是那个新的日期API。然后现在很多接口都是函数式接口,函数式接口下面都有一个这个注解,It function interface。所以说只要有这个注点,我们就认为它是一个函数式接口,如果这个现在的roundable接口就是一个函数式接口。原来我们之前写一个。
01:00
就是写一个round包的话,启动,然后你可是这样写的。就是那new,然后new一个。Run。你看这个是比较麻烦嘛,然后他就有一个方法,然后GDK1.8之后就可以直接用一个。对括号,然后减号,括号间号,然后直接写你的内容,非常的简洁,这种方法。然后是主要为了我们使方便使用这个拉姆达表达式,JAVA8提供了一些函数式的接口,就是这些消费型,供给型,函数型,判断型,然后我来举个例子啊,就是为什么需要这些函数式的接口呢?这个是我这个建了一个person类,建了一个person类,然后有那位置他的工资嘛,然后假如说有一个需求。就老板让你找出年龄大于20的员工,年龄大于20的员工,你立马就这个应该很简单吧,然后大多数人立马就写出来了,就把这个list传进去,然后判断它的H大于30,大于的话,再把它加到那个result list里面,然后再返回。
02:16
是吧,很快吧,然后在老板又发话了,就是你给我找一下大于2000的工资大于2000的员工吧,如果还是同样的啊。你就只不过是这个条件变了一下,就是他的工资大于2000,然后你把它加入这个result list里面。然后老板又发话了,再给我找一下什么什么条件吧。然后你还。你该怎么写呢?你再写一个这个list吗?这个不现实的,这个代码太勇于了,因为只有这一部分是不一样的啊,其他的逻辑一模一样,就是可扩展性太大太差,你知道吗?就是我们应该怎么优化呢?就是可以定义一个如下的接口,就是判断的逻辑,让接口的类去实现,还是按照上面的例子啊,我举了一个这个,写了一个这个接口。
03:11
写了一个这个test test,这个就是test。就是里面那个。你要判断的条件,你看我这个和前面一样啊,然后这个是一个条件,然后调用它接口的test,然后如果满足的话,满足这个条件的话,返回处,然后加到它里面,所以说我们看一下我们原来的结果就是变成这种了。Filter list,然后当大于年龄大于20的话,你传入一个这个年龄大于工资大于2000的话,传入这个条件,直接传一个条件,你知道吗?所以说不管老板再加什么需求的话,你都不不变了,这个因为你这个函数完全可以复用嘛。
04:00
你看我们这个定义的接口。和JAVA8内置的函数接口啊看一下。是一模一样诶。这个是我们定义的啊,Java定义的函数是接口啊。你看就是这个text几乎一模一样,真的是一模一样,它它这些定义的这些函数式接口就是。他JDK帮我们定义了接口,省得我们自己去定义,你看假如说有这样的需求,你每次还得定义一个这个判断条件的函数,比较麻烦嘛,所以说它内置的一些函数是接口。它有四种,四种类型的函数式接口,一个就是consumer消费型的,然后一个就是它就是传入一个T没有返回,还有个供给型,传入一个就直接可以获取到值,你不用传任何参数,然后就是一个函数型接口,就是传传入参数为T,返回为R,然后判断型,判断型我们就刚才演示了嘛,对象是否满足条件,初为满足,False为不满足。
05:11
还是来举几个例子啊,演示一下,就是这个是消费型的,你看我们传了一个消费型的,消费型的接口,消费型的接口,然后我们消费型的接口实际上在这儿就是直接把这个把这个值打印出来嘛,所以说你就会看到传入这个值,然后输出一个值,这个是一个,这个是一个函数型的接口嘛,传入一个值,然后返回另一个值。你传入一个A,它做的话就是把这个把这个值变成大写,就返回大写的AAA。就是。JAVA8还有很多其他内置的函数式接口,就是你可以看它的入参和返回的这个参数啊,就可以知道它这个接口的作用了。我举个例子,比如说这个吧,这个它肯定就是传入两个参数T或U,然后返回它的R。
06:04
这个的话就是传入T后U,然后没有返回。基本上看这个就可以知道它的大概作用了。好了,这个函数式接口我们就介绍到这了。下面我们来正式介绍这个stream。就是的话就是。基于这个函数式编程和拉姆达表达式就是。特别用起来特别爽,因为它是函数式编程嘛,然后stream的操作是分为三个步骤啊,分为三个步骤,第一个步骤创建stream,就是从数据源,例如集合数组获取一个流,然后中间操作对数据进行处理,然后还有就是终止操作,就是直接中间操作并产生结果。就是一般会返回一个word或一个非流的结果。还有注意的啊。不执行终止操作的时候,中间操作不会执行啊,举个例子啊,就是这个这个是我们创建的一个速度嘛,然后这个是date list,获取一个理由,然后对它进行一个map,后面这些具体的工作会解释的,就先可以看一下这个。
07:14
他其实没有,他其实这一部分算创建操作,Map是算中间操作,它没有终止操作,所以它虽然你看有输出语句,但是它其实并没有输出的,看第二个这个是创建操作,Map是中间操作,Collect是终止操作,所以说它会。会把这些list里面的值输出出来。好,我们来看一下,一步一步看,从这个创建操作开始看啊,创建stream的话有五种方式,第一个就是collection点或。这个你看我弄了一个list list.stream就是函数,就是collection集合都可以用点stream可以把它函数STEM流串联出来。
08:01
还有一个就是静态数组,这个AR stream也是一种方法,还有一个stream the.of也可以啊,然后还有一个就是stream。这个是一个创建无限流啊,相当于就是。你传入一个零零,它会返回这个零,然后零加二等于二,然后再把这个二作为这个第二次的入参二。加二等于四,再流出出来四,反正一直就是最后一直会输出零二四六八十十二,这样还有一个创建。创建无限流吗?创建无限流。创建无限流,这个这个是创建无限流,就是这个这个流里面的值永远是十啊。就是你调用一次。你看它会返回一个十,它就会一直就就是会一直输出十,就一直会输十。
09:06
好了,创建操作的话,大家可以根据我这个写个DEMO,我就不做演示了嘛,因为时间比较短,然后第二个的话就是中间操作,中间操作的话就是由这几个比较重要,就filter从流中排除元素,Limit就是最限制嘛,然后SK就是跳过前N个元素,Distinct就是equals聚种元素,这个就是你看啊,这个就是1212嘛,然后我们只输出基数啊,只输出基数啊,你看filter就是进行过滤嘛,只输出基数的话,它就输出一三,跳过前两个就是1234嘛,就是跳过前两个就是三四。还有一个这个这个是啥。A和for it。你可看到这个stream for each for each的话是我们打印嘛,你一般不怎么打印,但是for each的话,你可以看这个for each,它其实就是一个函数式接口,它其实就是一个消费型的接口嘛,就是你传入一个值。
10:12
然后把这个纸给打印出来。对,中间操作第一个就是筛选与贴片,然后就是这些,然后还有做一个映射,映射的话就是一个map和一个Fla map map的话就是相当于我们对一个元素做操作,然后另映射成另一个元素啊。可以看一下。就是你看这个。嗯。对对对,然后Fla map法就是将多个流打平,然后输出成一个流,举个例子啊,这个就是我们得到一个流嘛,然后把这个流split split后为两个数组嘛,这两个就为两个数组,然后输出这两个数组,你看就把这两个数组的地址给输入出来了。
11:00
Map的话,你看还是原来这个,这个是为输出打。这个r.STEM。点split,它就把多个数组,然后弄成多个流,就是多个流flight map会把多个流合并成一个流,然后再打印出来,所以说它这个的打印输出结果是这个。数组的地址,这个就是。对,这个是多个数组,然后合并成一个零打印出来,然后还有一个排序操作,排序操作的话也比较简单,你看就是这个是自然的排序啊,自然排序就是按照那个。ABC嘛,返回,然后我们可以定制它的排序规则啊,通过通过这个comp接口,它其实也是一个函数式接口,然后我们在这里面传了嘛,然后就是它是一个降序排的,所以会返回CBA,好最后看这个终止操作,终止操作的话。
12:00
也其实有很多宗旨操作,你我就举个例子,我不说太多啊,就是all match就是是否匹配所有元素,Any match是否至少匹配一个元素啊,这个应该比较容易理解吧,No match就是没有匹配所有的元素。如果你看这个得到一个LIST1234。我们用一个list string.match是否所有的元素都等于肯定不回,肯定是first,因为这这个list全为一的话,它才会返回true嘛,因为它所有都是一嘛,然后一个any,这个是any match,只要它数组中有一个数为一,它就返回true嘛,这个肯定回处嘛,这个的话是。MAT。啊,这个是它这个是一个排序的嘛,这个是一个排序的。获取它的返回流中的最大值,返回流中的最大值。
13:00
流动最大值不就是四嘛,对,终止差错一个就是查找与匹配,然后还有一个规约,规约的话就是将流中元素法握结合起来,得到一个值啊。嗯,你看这个规约函数的话,你可以看出它是初始的时候,0X加Y就是零加二。零加二得到零不是零加一,得到一一加二。得到三三加三得到六六加四得到十。就是这样一个过程,这个在大数据中比较常用啊。这个在大数据中非常常用,但是我们平时的话用不着这么写。还有一个就是收集。收集的话是收集的话是需要你。就是它这个时间比较麻烦,所以说有也是有两个函数,我们就是,但是就是。Java吧,提供了一些内置的收集内置的工具类嘛,就像我们那个创建线程池的话,参数比较多,你自己创建起来比较麻烦,它要给你创建了一个工具类嘛,就是collectors工具类。
14:10
好,这个student,来,我们来看几个例子,就是student name。然后我用一个用一个,嗯,好吧好吧,我换一个这个比较短,我看看一下我博客吧。就是我们历卡。举还是举例子啊,就是这个这个不是放到一个list里面了吗?张三30,李四20,王五20,就是那个位置,然后想获得他的所有的名字啊,那个student stream map map,就是对每个元素做操作嘛,获取他的名字,然后收集到一个list里面。李四里面张三李四王五,然后可以搜,当然还可以收集到site里面,Site里面它会自动去除的,你看这个三十二十二十去除完就是就是年龄就是二十三十嘛。
15:01
当然,我们还可以。就是我们想指定它那种集合的类型的话,你完全就可以啊,你collect.collection你看就site的话,我们用哈site,你这样就就可以了。Link哈,然后还有一个,还有一个很多嘛,还有一个就是它的总数对总数。总数COUNT3,然后平均值,一些平均值,收集的一些平均值,收集的总和,收集的最大值。年龄分组就是按年龄分组,你可以看一下,按年龄分组的话就是stream.collection group student age,你看年龄分完组之后的话,20算一个组,然后有两个对象,30有一个组算有一个对象,还有可以你可以再嵌套嘛,就是嵌套多层,然后例可以,这个例子也就分成多级多个组嘛,分成多级分组,这个你可以写个DEMO,我不再不再做演示了。
16:01
我最后再举几个比较常用的例子啊,常用的例子啊。这个的话。一个就是枚举值校验,假如说一些就是当选环之类的话,我们在后后端是用那个。后端是用的这个枚举来做的,但是前端的参数你要进行做校验,还有个假如说前端模传入的参数,传入的参数为一,你要对这个参数做一下校验,是不是在我们这个枚举之中,你就可以这样加stream枚举的value,看它是否有其至少有一个为一,你看肯定是true嘛。假如说你看它传前端传入的是五嘛,就没有不在我们这里面就返回一个false,这个就是很方便嘛,假如说你自己去判断呢,还记得写一份一很多一二,还有就是调用钱存这种对应关系啊。我们经常需要。
17:00
调用其他服务来获取一些其他的信息,假如说我们有一个student,然后需要调用其他服务获取student的其他信息,然后再填充到这个student里面。就是调用批量接口的时候,这个场景真的很常用啊,所以说我们就先存一下这个学生姓名和学生的映射关系为内map,你看这就是我创建了三个student吗?那用map就是。就是学生的姓名和学生这个对象做的映射,比如collect student collect to这个学生的姓名student student,然后。就把这个学生姓名和学生这个对象的映射关系放到这个map里面来,然后再用学生的姓名去调用其他服务,返回其他信息,再填充到根据这个map填充到这个student对象里面。对,然后。这个stream的内容就介绍到这里吧。
18:03
嗯,大家有兴趣的话,可以看看这个链接,找这个链接,找我这个链接。然后看一下,看一下这篇文章,这篇文章的阅读数还是挺高的吧。
我来说两句