13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介

目录

    • 1. 流式思想的概述
      • 1.1 传统方式遍历集合
      • 1.2 Stream流遍历集合
      • 1.3 流式思想
    • 2. Stream流中的常用方法
      • 2.1 获取Stream流
      • 2.2 forEach方法
      • 2.3 filter方法
      • 2.4 map方法
      • 2.5 count方法
      • 2.6 limit方法
      • 2.7 skip方法
      • 2.8 concat方法
    • 3. 方法引用

1. 流式思想的概述

在介绍流式思想是什么之前,我们先来感受一下Stream流的使用的便利,下面以集合遍历为例子进行介绍

1.1 传统方式遍历集合

众所周知,如果想要对一个集合进行遍历,那么我们可以采用普通for循环、增强for循环和迭代器,这里以增强for循环为例子,另外,当我们想要对集合的数据进行过滤的时候,第一个想到的便是if语句,现在我们的需求是,有一个储存了多个个人名字与性别的数组,我要从中筛选出名字是由3个字母组成的女生并打印其信息,下面来看看实现该功能的示例程序
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第1张图片
其运行结果
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第2张图片

1.2 Stream流遍历集合

这里先不介绍Stream流的用法,先感受一下实现上述功能的代码是怎么样子的
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第3张图片
其运行结果是一样的
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第4张图片
是不是感觉代码变简单了,不需要for循环,也不需要if判断语句,这就是采用Stream流的方式来实现,下面来详细介绍一下什么是Stream流与流式思想

1.3 流式思想

流式思想的实质其实跟流水线操作参不多,流水线上有众多的产品,当他经过每个工位的时候需要执行不同的操作,最后输出成品,而这里我们所介绍的Stream流可以理解为流水线上的产品,是不是很抽象?来看个图
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第5张图片
Stream流其实是一个集合元素的函数模型,他不是集合,也不是数据结构,他本身也并不储存任何元素或者是地址值,当使用一个流的时候,通常包括三个基本步骤获取一个数据源 --> 数据转换 --> 执行操作获取想要的结果,每次转换原有Stream对象不改变,返回一个新的Stream对象(可以有多次转换),这样就允许对其操作像流水线一样

2. Stream流中的常用方法

下面就来了解一下Stream流的获取方式和常用方法

2.1 获取Stream流

获取Stream流有两种方式:

  • 所有的Collection集合都可以通过其默认方法stream来获取流
public default Stream<E> parallelStream():返回可能并行的 Stream与此集合作为其来源。  
  • 可利用Stream接口的静态方法of获取相应数组的流
public static <T> Stream<T> of(T... values):返回其元素是指定值的顺序排序流。  
public static <T> Stream<T> of(T t) :返回包含单个元素的顺序 Stream 。  

这里分别演示一下两种不同的Stream流获取方式
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第6张图片
流类型的操作很丰富,下面介绍的是常用的方法,这些方法可以分成两种:

  • 延迟方法:返回值类型仍然Stream接口,因此支持链式调用(除了终结方法外,其它方法都是延迟方法)
  • 终结方法:返回值类型不再Stream接口,因此不支持链式调用,本文介绍的终结方法包括countforEach方法

2.2 forEach方法

为什么要先给你们介绍一个终结方法呢?因为后续其它方法的学习我们都要利用到终结方法来查看结果

public void forEach(Consumer<? super T> action):对此流的每个元素执行操作。 

可见,forEach方法所需要传递的参数是上篇文章中介绍的一个Consumer函数式接口,这是一个消费型接口,换言之,forEach方法会把每一个流元素交给Consumer接口来消费,这里我们来演示一下对数据直接打印输出
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第7张图片
其运行结果
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第8张图片

2.3 filter方法

filter方法,相信你也能猜到他是一个流元素的过滤器

public Stream<T> filter(Predicate<? super T> predicate):返回由与此给定谓词匹配的此流的元素组成的流。 

毫无悬念,这个方法所传递的又是上篇文章中介绍的Predicate接口,这里我们来演示一下把个人信息数组中姓名首字母为J的个人信息打印出来
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第9张图片
其运行结果
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第10张图片

2.4 map方法

说起map是不是会想起双列集合Map呢?其实这个map方法也有一点点那么个意思

public<R> Stream<R> map(Function<? super T,? extends R> mapper) 
返回由给定函数应用于此流的元素的结果组成的流。 

可见,这个方法所需要传递的是一个Function接口,换言之就是把流中的元素映射到另外一个流上,可以理解为可进行数据转换,这里我们演示一下把字符串格式的数字转换为整形,为了证明转换后的是整形数据,输出时对其进行 +1输出(字符串不能+1)
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第11张图片
其运行结果
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第12张图片

2.5 count方法

你们一定想到这个方法是计数的对不对?那么既然都计数了,返回值肯定不是Stream了,因此这是一个终结方法

public long count() :返回此流中的元素数。  

这个方法不用过多介绍啦,直接来演示一下
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第13张图片
其运行结果
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第14张图片

2.6 limit方法

limit即是限制,就是可以理解为我只要前几个元素

public Stream<T> limit(long maxSize):返回由此流的元素组成的流,截短长度不能超过 maxSize 。  

注意,如果集合当前长度大于参数则进行截取操作,否则不进行操作,下面来看演示
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第15张图片
其运行结果
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第16张图片

2.7 skip方法

这个方法你们也会想到跳过对不对

public Stream<T> skip(long n) :在丢弃流的前n个元素后,返回截取后的流。  

注意,如果流的当前长度大于n,则跳过前n个,否则会得到一个长度为0的流,下面看一下演示
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第17张图片
其运行结果
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第18张图片

2.8 concat方法

还记得String类中也有一个concat方法用于字符串拼接吗?这里的concat方法也是拼接的作用

public static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b):创建一个懒惰连接的流,其元素是第一个流的所有元素,后跟第二个流的所有元素。 

废话不多说,看看演示
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第19张图片
其运行结果
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第20张图片

3. 方法引用

我们之前在学习过程中一直都是调用某个方法去完成某些功能,即方法调用,那么方法引用又是什么东西呢?

双冒号::引用运算符,而它所在的表达式也被称为方法引用。如果Lambda要表达的函数方案已经在某个方法中实现,那么则可以通过双冒号来引用该方法作为Lambda的替代者,说白了,这其实又是对Lambda表达式的一个优化

似乎有点抽象,到底是什么意思呢,下面给出两种写法,其实是完全等效的:

  • Lambda表达式写法:s -> System.out.println(s)
  • 方法引用写法:System.out::println

别的不说,从形式上看起来是不是已经是简洁很多呢?细心的同学可能也发现了前文介绍Stream流的方法中我给出的示例程序的打印语句s -> System.out.println(s)都是不同颜色的,这其实就是IDEA在提示我们可以用方法引用对其进行优化

例如map方法中的程序优化前是这样的
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第21张图片
优化后是这样的
13. Java入门之Stream流是什么?流式思想的概述、Stream流中的常用方法、方法引用简介_第22张图片
细心的同学又发现了,为什么这里的System.out.println不可以用方法引用进行优化呢?发现了吗?为什么呢?因为这里传递进去Lambda表达式的是p,而我想要打印的是p+1,严格意义上来说,它们不是同一个东西,换言之,当它们不是同一个东西的时候,就不能进行推断

再说明白一点,还是以打印语句为例子,在Lambda表达式写法中是s -> System.out.println(s),其意思是我把传进来的字符串命名s,然后打印命名为s的字符串,则这个s其实就是一个形参,可以说没有意义,那么其实我只需要知道你调用了谁(System.out)的什么方法(println)来处理那个传递进来的东西就好了,我就不需要再写一个形式参数那么麻烦了,因此就有了方法引用的简化System.out::println,无论你传递什么进来我都用System.out中的println来对其进行处理,也正是因为如此,所以传递进来的参数一定要是方法引用中的方法可以接受的类型,否则会抛出异常,在这个表达式中双冒号前的就是被调用的对象,双冒号后的就是方法

我相信我已经说得很明白了,如果还不太懂的同学也不用怕,你只需要知道是个什么意思就好了,如果确实要写的话,你可以先写个Lambda表达式,IDEA可以给你自动转过去(手动狗头)

好啦,这篇文章结束啦啦啦啦啦啦~

你可能感兴趣的:(Java入门)