前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring-Web-Flux实战(三) - Stream 流

Spring-Web-Flux实战(三) - Stream 流

作者头像
JavaEdge
发布2019-03-04 10:59:47
1.3K0
发布2019-03-04 10:59:47
举报
文章被收录于专栏:JavaEdgeJavaEdge

相关源码

1 Stream流编程-概念

Stream是 Java 8新增加的类,用来补充集合类。

Stream代表数据流,流中的数据元素的数量可能是有限的,也可能是无限的。

Stream和其它集合类的区别在于

  • 其它集合类主要关注与有限数量的数据的访问和有效管理(增删改)
  • Stream并没有提供访问和管理元素的方式,而是通过声明数据源的方式,利用可计算的操作在数据源上执行 当然BaseStream.iterator() 和 BaseStream.spliterator()操作提供了遍历元素的方法
  • 不存储数据 流是基于数据源的对象,它本身不存储数据元素,而是通过管道将数据源的元素传递给操作。 函数式编程。流的操作不会修改数据源,例如filter不会将数据源中的数据删除。
  • 延迟操作 流的很多操作如filter,map等中间操作是延迟执行的,只有到终点操作才会将操作顺序执行。
  • 可以解绑 对于无限数量的流,有些操作是可以在有限的时间完成的,比如limit(n) 或 findFirst(),这些操作可是实现"短路"(Short-circuiting),访问到有限的元素后就可以返回。
  • 纯消费 流的元素只能访问一次,类似Iterator,操作没有回头路,如果你想从头重新访问流的元素,对不起,你得重新生成一个新的流

Java Stream提供了提供了串行和并行两种类型的流,保持一致的接口,提供函数式编程方式,以管道方式提供中间操作和最终执行操作,为Java语言的集合提供了现代语言提供的类似的高阶函数操作,简化和提高了Java集合的功能

2 流的创建

创建

3 流的中间操作

中间操作会返回一个新的流,并且操作是延迟执行的,它不会修改原始数据源,而是由在终点操作开始的时候才真正开始执行 这和Scala集合的转换操作不同,Scala集合转换操作会生成一个新的中间集合,显而易见Java的这种设计会减少中间对象的生成

3.1 map

Stream#map

ReferencePipeline#map

将流中的元素映射成另外的值,新的值类型可以和原来的元素的类型不同

下面的代码中将字符元素映射成它的哈希码(ASCII值)

代码语言:javascript
复制
List<Integer> l = Stream.of('a','b','c')
        .map( c -> c.hashCode())
        .collect(Collectors.toList());
System.out.println(l); //[97, 98, 99]

3.2 flatMap

flatmap方法混合了map + flattern的功能,它将映射后的流的元素全部放入到一个新的流中 mapper函数会将每一个元素转换成一个流对象,而flatMap方法返回的流包含的元素为mapper生成的所有流中的元素

下面这个例子中将一首唐诗生成一个按行分割的流,然后在这个流上调用flatmap得到单词的小写形式的集合,去掉重复的单词然后打印出来

代码语言:javascript
复制
String poetry = "Where, before me, are the ages that have gone?\n" +
        "And where, behind me, are the coming generations?\n" +
        "I think of heaven and earth, without limit, without end,\n" +
        "And I am all alone and my tears fall down.";
Stream<String> lines = Arrays.stream(poetry.split("\n"));
Stream<String> words = lines.flatMap(line -> Arrays.stream(line.split(" ")));
List<String> l = words.map( w -> {
    if (w.endsWith(",") || w.endsWith(".") || w.endsWith("?"))
        return w.substring(0,w.length() -1).trim().toLowerCase();
    else
        return w.trim().toLowerCase();
}).distinct().sorted().collect(Collectors.toList());,
System.out.println(l); //[ages, all, alone, am, and, are, before, behind, coming, down, earth, end, fall, generations, gone, have, heaven, i, limit, me, my, of, tears, that, the, think, where, without]

3.3 filter

返回的流中只包含满足断言(predicate)的数据

下面的代码返回流中的偶数集合

代码语言:javascript
复制
List<Integer> l = IntStream.range(1,10)
        .filter( i -> i % 2 == 0)
        .boxed()
        .collect(Collectors.toList());
System.out.println(l); //[2, 4, 6, 8]

3.4 peek

会使用一个Consumer消费流中的元素,但是返回的流还是包含原来的流中的元素。

代码语言:javascript
复制
String[] arr = new String[]{"a","b","c","d"};
Arrays.stream(arr)
       .peek(System.out::println) //a,b,c,d
       .count();

下面是有状态操作

3.5 distinct

保证输出的流中包含唯一的元素,它是通过Object.equals(Object)来检查是否包含相同的元素

代码语言:javascript
复制
List<String> l = Stream.of("a","b","c","b")
        .distinct()
        .collect(Collectors.toList());
System.out.println(l); //[a, b, c]

3.6 sorted

将流中的元素按照自然排序方式进行排序,如果元素没有实现Comparable,则终点操作执行时会抛出java.lang.ClassCastException异常 sorted(Comparator<? super T> comparator)可以指定排序的方式。

对于有序流,排序是稳定的。对于非有序流,不保证排序稳定。

代码语言:javascript
复制
String[] arr = new String[]{"b_123","c+342","b#632","d_123"};
List<String> l  = Arrays.stream(arr)
        .sorted((s1,s2) -> {
            if (s1.charAt(0) == s2.charAt(0))
                return s1.substring(2).compareTo(s2.substring(2));
            else
                return s1.charAt(0) - s2.charAt(0);
        })
        .collect(Collectors.toList());
System.out.println(l); //[b_123, b#632, c+342, d_123]

3.7 skip

返回丢弃了前n个元素的流,如果流中的元素小于或者等于n,则返回空的流

3.8 limit

指定数量的元素的流。对于串行流,这个方法是有效的,这是因为它只需返回前n个元素即可,但是对于有序的并行流,它可能花费相对较长的时间,如果你不在意有序,可以将有序并行流转换为无序的,可以提高性能。

代码语言:javascript
复制
List<Integer> l = IntStream.range(1,100).limit(5)
        .boxed()
        .collect(Collectors.toList());
System.out.println(l);//[1, 2, 3, 4, 5]

4 流的终止操作

4.1 非短路操作

  • forEach、forEachOrdered forEach遍历流的每一个元素,执行指定的action。它是一个终点操作,和peek方法不同。这个方法不担保按照流的encounter order顺序执行,如果对于有序流按照它的encounter order顺序执行,你可以使用forEachOrdered方法
代码语言:javascript
复制
Stream.of(1,2,3,4,5).forEach(System.out::println);
  • toArray 将流中的元素放入到一个数组中
  • collect

使用一个collector执行mutable reduction操作 辅助类Collectors提供了很多的collector,可以满足我们日常的需求,你也可以创建新的collector实现特定的需求。它是一个值得关注的类,你需要熟悉这些特定的收集器,如聚合类averagingInt、最大最小值maxBy minBy、计数counting、分组groupingBy、字符串连接joining、分区partitioningBy、汇总summarizingInt、化简reducing、转换toXXX等。

第二个提供了更底层的功能,它的逻辑类似下面的伪代码:

代码语言:javascript
复制
R result = supplier.get();
for (T element : this stream)
    accumulator.accept(result, element);
return result;

例子

代码语言:javascript
复制
List<String> asList = stringStream.collect(ArrayList::new, ArrayList::add,
                                           ArrayList::addAll);
String concat = stringStream.collect(StringBuilder::new, StringBuilder::append,
                                     StringBuilder::append)
                            .toString();
  • reduce 是常用的一个方法,事实上很多操作都是基于它实现的。 它有几个重载方法
代码语言:javascript
复制
Optional<Integer> total = Stream.of(1,2,3,4,5).reduce( (x, y) -> x +y);
Integer total2 = Stream.of(1,2,3,4,5).reduce(0, (x, y) -> x +y);

值得注意的是accumulator应该满足结合性(associative)

  • max、min max返回流中的最大值 min返回流中的最小值

5 并行流(Parallelism)

所有的流操作都可以串行/并行执行 除非显示地创建并行流,否则Java库中创建的都是串行流 Collection.stream()为集合创建串行流而Collection.parallelStream()为集合创建并行流 IntStream.range(int, int)创建的是串行流 通过parallel()方法可以将串行流转换成并行流,sequentia()方法将流转换成串行流。

除非方法的Javadoc中指明了方法在并行执行的时候结果是不确定(比如findAny、forEach),否则串行和并行执行的结果应该是一样的。

示例

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019.02.12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 相关源码
  • 1 Stream流编程-概念
  • 2 流的创建
  • 3 流的中间操作
    • 3.1 map
      • 3.2 flatMap
        • 3.3 filter
          • 3.4 peek
          • 下面是有状态操作
            • 3.5 distinct
              • 3.6 sorted
                • 3.7 skip
                  • 3.8 limit
                  • 4 流的终止操作
                    • 4.1 非短路操作
                    • 5 并行流(Parallelism)
                      • 示例
                      领券
                      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档