stream流常用方法(java stream详解)

健康新闻 2023-05-01 10:07健康生活www.xingbingw.cn

  stream流常用方法(java stream详解),新营销网红网本栏目通过数据整理汇集了stream流常用方法(java stream详解)相关信息,下面一起看看。

   1.第一次体验流。让我们先来看看Java是如何定义stream的

  支持顺序和并行聚合操作的元素序列。

  我们来解读一下上面这句话

  是Stream元素,让流看起来像迭代器;

  可以支持原始流的顺序和并行聚合;

  你可以把Stream看作迭代器的高级版本。在迭代器的原始版本中,用户只能逐个遍历元素,并对其执行某些操作;Stream的高级版本,用户只需要给出需要对其包含的元素进行哪些操作,比如“过滤掉长度大于10的字符串”、“获取每个字符串的首字母”等。只要把它们交给Stream,这些操作是如何应用到每个元素上的!(这个作弊,我不告诉一般人)看完这些你可能对Stream没有直观的认识。别急,咱们来个暗号。

   //Lists是Guava中的工具类。

   list Integer nums=lists . newarraylist(1,null,3,4,null,6);

   nums.stream()。过滤器(num - num!=null)。count();

  上面的代码是获取一个列表中非空元素的数量。虽然这段代码很短,但它是展示如何使用Stream的一个很好的入门级示例。俗话说“麻雀虽小,五脏俱全”。现在,让我们深入这个例子。完成后,你可能就能基本掌握Stream的用法了!

  解析流常规语法

  图为流例分析,可以清楚的看到原句被三个彩色方框分成三部分。红框中的语句是流的生命开始的地方,负责创建流实例;绿框中的语句是给予流的灵魂的地方,一个流转换成另一个流。红框中的语句生成一个包含所有nums变量的流。通过绿框中的过滤器后,原始nums列表中的所有null被过滤掉后,重新生成一个流。蓝框中的语句是大丰收的地方,流中包含的内容按照某种算法聚合成一个值。在该示例中,获取了流中包含的元素数量。如果你分析完这个还不明白,那就只能用“核武器”——图形化,一张图胜过千言万语!

  这里我们一下使用Stream的基本步骤

  创建一个流;

   Convert Stream,每次不改变原来的Stream对象,返回一个新的Stream对象( 可以有多次转换 );

  减少流以获得期望的结果;

   2.创建流有两种最常用的方法

  静态工厂通过流接口(注意接口在Java8中可以是静态的);

  通过集合接口的默认(default: Default method,这也是Java8中的一个新特性,也就是在接口中有实现的一个,后面文章会介绍)-Stream(),将一个集合对象转换成Stream。

   2.1使用流静态创建流

   1.of:有两个重载,一个接受可变长度参数,另一个接口接受单个值。

   1 stream Integer Integer stream=stream . of(1,2,3,5);

   2 stream String String stream=stream . of(淘宝

   2.生成器生成一个无限长的流,它的元素是通过给定的提供者生成的(这个接口可以看作是一个对象工厂,每个调用返回一个给定类型的对象)

   Stream.generate(新供应商Double () {

   @覆盖

   public Double get() {

  返回math . random();

   }

   });

   stream . generate(()-math . random());

   stream . generate(math : random);

  除了使用lambda表达式和引用的语法来简化代码之外,这三个语句具有相同的功能。每个语句实际上都生成一个无限长的流,其中的值是随机的。这个无限长的流是延迟加载的。通常,这个无限长的流将与流的limit()一起使用。

   3.iterate:它还生成一个无限长的流。与generator不同,其元素的生成是通过针对给定的种子值(seed)重复调用用户指定的函数来生成的。其中包含的元素可以认为是seed,f(seed),f(f(seed))无限循环。

   1Stream.iterate(1,item - item 1)。极限(10)。forEach(system . out :3360 println);

  这段代码是先得到一个无限长的正整数流,然后把前10个拿出来打印出来。一千万

  记住使用limit ,不然会无限打印下去。

  2.2 通过Collection子类获取Stream

  这个在本文的第一个例子中就展示了从List对象获取其对应的Stream对象,如果查看Java doc就可以发现Collection接口有一个stream ,所以其所有子类都都可以获取对应的Stream对象。

  1public interface Collection E extends Iterable E {

  2 //其他 省略

  3 default Stream E stream() {

  4 return StreamSupport.stream(spliterator(), false);

  5 }

  6}

  3. 转换Stream

  转换Stream其实就是把一个Stream通过某些行为转换成一个新的Stream。Stream接口中定义了几个常用的转换 ,下面我们挑选几个常用的转换 来解释。

  1. distinct: 对于Stream中包含的元素进行去重操作(去重逻辑依赖元素的equals ),新生成的Stream中没有重复的元素;

  distinct 示意图(以下所有的示意图都要感谢[RxJava](https://github.com/Netflix/RxJava)项目的doc中的图片给予的灵感, 如果示意图表达的有错误和不准确的地方,请直接联系我。)

  2. filter: 对于Stream中包含的元素使用给定的过滤函数进行过滤操作,新生成的Stream只包含符合条件的元素;

  filter 示意图

  3. map: 对于Stream中包含的元素使用给定的转换函数进行转换操作,新生成的Stream只包含转换生成的元素。这个 有三个对于原始类型的变种 ,分别是mapToInt,mapToLong和mapToDouble。这三个 也比较好理解,比如mapToInt就是把原始Stream转换成一个新的Stream,这个新生成的Stream中的元素都是int类型。之所以会有这样三个变种 ,可以免除自动装箱/拆箱的额外消耗;

  map 示意图

  4. flatMap和map类似,不同的是其每个元素转换得到的是Stream对象,会把子Stream中的元素压缩到父 中;

  flatMap 示意图

  5. peek: 生成一个包含原Stream的所有元素的新Stream,会提供一个消费函数(Consumer实例),新Stream每个元素被消费的时候都会执行给定的消费函数;

  peek 示意图

  6. limit: 对一个Stream进行截断操作,获取其前N个元素,如果原Stream中包含的元素个数小于N,那就获取其所有的元素;

  limit 示意图

  7. skip: 返回一个丢弃原Stream的前N个元素后剩下元素组成的新Stream,如果原Stream中包含的元素个数小于N,那么返回空Stream;

  skip 示意图

  8. 在一起,在一起!

  1List Integer nums = Lists.newArrayList(1,1,null,2,3,4,null,5,6,7,8,9,10);

  2System.out.println(“sum is:”+nums.stream().filter(num - num != null).

  3 distinct().mapToInt(num - num 2).

  4 peek(System.out::println).skip(2).limit(4).sum());

  这段代码演示了上面介绍的所有转换 (除了flatMap),简单解释一下这段代码的含义给定一个Integer类型的List,获取其对应的Stream对象,然后进行过滤掉null,再去重,再每个元素乘以2,再每个元素被消费的时候打印自身,在跳过前两个元素,去前四个元素进行加和运算(解释一大堆,很像废话,因为基本看了 名就知道要做什么了。这个就是声明式编程的一大好处!)。大家可以参考上面对于每个 的解释,看看最终的输出是什么。

  9. 性能问题

  有些细心的同学可能会有这样的疑问在对于一个Stream进行多次转换操作,每次都对Stream的每个元素进行转换,而且是执行多次,这样时间复杂度就是一个for循环里把所有操作都做掉的N(转换的次数)倍啊。其实不是这样的,转换操作都是lazy的,多个转换操作只会在汇聚操作(见下节)的时候融合起来,一次循环完成。我们可以这样简单的理解,Stream里有个操作函数的 ,每次转换操作就是把转换函数放入这个 中,在汇聚操作的时候循环Stream对应的 ,然后对每个元素执行所有的函数。

  4. 汇聚(Reduce)Stream

  汇聚这个词,是我自己翻译的,如果大家有更好的翻译,可以在下面留言。在官方文档中是reduce,也叫fold。

  在介绍汇聚操作之前,我们先看一下Java doc中对于其定义

  A reduction operation (also called a fold) takes a sequence of input elements and combines them into a single summary result by repeated application of a combining operation, such as finding the sum or maximum of a set of numbers, or accumulating elements into a list. The streams classes have multiple forms of general reduction operations, called reduce() and collect(), as well as multiple specialized reduction forms such as sum(), max(), or count().

  简单翻译一下汇聚操作(也称为折叠)接受一个元素序列为输入,反复使用某个合并操作,把序列中的元素合并成一个汇总的结果。比如查找一个数字列表的总和或者最大值,或者把这些数字累积成一个List对象。Stream接口有一些通用的汇聚操作,比如reduce()和collect();也有一些特定用途的汇聚操作,比如sum(),max()和count()。注意sum 不是所有的Stream对象都有的,只有IntStream、LongStream和DoubleStream是实例才有。

  下面会分两部分来介绍汇聚操作

  可变汇聚把输入的元素们累积到一个可变的容器中,比如Collection或者StringBuilder;

  其他汇聚除去可变汇聚剩下的,一般都不是通过反复修改某个可变对象,而是通过把前一次的汇聚结果当成下一次的入参,反复如此。比如reduce,count,allMatch;

  4.1 可变汇聚

  可变汇聚对应的只有一个 collect,正如其名字显示的,它可以把Stream中的要有元素收集到一个结果容器中(比如Collection)。先看一下最通用的collect 的定义(还有其他override )

  1 R R collect(Supplier R supplier,

  2 BiConsumer R, ? super T accumulator,

  3 BiConsumer R, R combiner);

  先来看看这三个参数的含义Supplier supplier是一个工厂函数,用来生成一个新的容器;BiConsumer accumulator也是一个函数,用来把Stream中的元素添加到结果容器中;BiConsumer combiner还是一个函数,用来把中间状态的多个结果容器合并成为一个(并发的时候会用到)。看晕了?来段代码!

  1List Integer nums = Lists.newArrayList(1,1,null,2,3,4,null,5,6,7,8,9,10);

  2 List Integer numsWithoutNull = nums.stream().filter(num - num != null).

  3 collect(() - new ArrayList Integer (),

  4 (list, item) - list.add(item),

  5 (list1, list2) - list1.addAll(list2));

  上面这段代码就是对一个元素是Integer类型的List,先过滤掉全部的null,然后把剩下的元素收集到一个新的List中。进一步看一下collect 的三个参数,都是lambda形式的函数(上面的代码可以使用 引用来简化,留给读者自己去思考)。

  第一个函数生成一个新的ArrayList实例;

  第二个函数接受两个参数,第一个是前面生成的ArrayList对象,二个是stream中包含的元素,函数体就是把stream中的元素加入ArrayList对象中。第二个函数被反复调用直到原stream的元素被消费完毕;

  第三个函数也是接受两个参数,这两个都是ArrayList类型的,函数体就是把第二个ArrayList全部加入到第一个中;

  上面的collect 调用也有点太复杂了,没关系!我们来看一下collect 一个override的版本,其依赖[Collector](http://docs.oracle.com/javase/8/docs/api/java/util/stream/Collector.html)。

  1 R, A R collect(Collector ? super T, A, R collector);

  这样清爽多了!少年,还有好消息,Java8还给我们提供了Collector的工具类–[Collectors](http://docs.oracle.com/javase/8/docs/api/java/util/stream/Collectors.html),其中已经定义了一些静态工厂 ,比如Collectors.toCollection()收集到Collection中, Collectors.toList()收集到List中和Collectors.toSet()收集到Set中。这样的静态 还有很多,这里就不一一介绍了,大家可以直接去看JavaDoc。下面看看使用Collectors对于代码的简化

  1List Integer numsWithoutNull = nums.stream().filter(num - num != null).

  2 collect(Collectors.toList());

  4.2 其他汇聚

  – reduce reduce 非常的通用,后面介绍的count,sum等都可以使用其实现。reduce 有三个override的 ,本文介绍两个最常用的,一个留给读者自己学习。先来看reduce 的第一种形式,其 定义如下

  1Optional T reduce(BinaryOperator T accumulator);

  接受一个BinaryOperator类型的参数,在使用的时候我们可以用lambda表达式来。

  1List Integer ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);

  2System.out.println( ints sum is: + ints.stream().reduce((sum, item) - sum + item).get());

  可以看到reduce 接受一个函数,这个函数有两个参数,第一个参数是上次函数执行的返回值(也称为中间结果),第二个参数是stream中的元素,这个函数把这两个值相加,得到的和会被赋值给下次执行这个函数的第一个参数。要注意的是第一次执行的时候第一个参数的值是Stream的第一个元素,第二个参数是Stream的第二个元素。这个 返回值类型是Optional,这是Java8防止出现NPE的一种可行 ,后面的文章会详细介绍,这里就简单的认为是一个容器,其中可能会包含0个或者1个对象。

  这个过程可视化的结果如图

  reduce 还有一个很常用的变种

  1T reduce(T identity, BinaryOperator T accumulator);

  这个定义上上面已经介绍过的基本一致,不同的是它允许用户提供一个循环计算的初始值,如果Stream为空,就直接返回该值。而且这个 不会返回Optional,因为其不会出现null值。下面直接给出例子,就不再做说明了。

  1List Integer ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);

  2System.out.println( ints sum is: + ints.stream().reduce(0, (sum, item) - sum + item));

  – count 获取Stream中元素的个数。比较简单,这里就直接给出例子,不做解释了。

  1List Integer ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);

  2System.out.println( ints sum is: + ints.stream().count());

  – 搜索相关

  – allMatch是不是Stream中的所有元素都满足给定的匹配条件

  – anyMatchStream中是否存在任何一个元素满足匹配条件

  – findFirst: 返回Stream中的第一个元素,如果Stream为空,返回空Optional

  – noneMatch是不是Stream中的所有元素都不满足给定的匹配条件

  – max和min使用给定的比较器(Operator),返回Stream中的最大

  最小值

  下面给出allMatch和max的例子,剩下的 读者当成练习。

  1List Integer ints = Lists.newArrayList(1,2,3,4,5,6,7,8,9,10);

  2System.out.println(ints.stream().allMatch(item - item 100));

  3ints.stream().max((o1, o2) - o1.compareTo(o2)).ifPresent(System.out::println);

  streamstream(Java 8中处理集合的优雅姿势——Stream)

  更多stream流常用方法(java stream详解)相关信息请关注本文章,本文仅仅做为展示!

Copyright@2015-2025 www.xingbingw.cn 性病网版板所有