• JAVA8新特性--集合流操作Stream


    原文链接:https://blog.csdn.net/bluuusea/article/details/79967039

    Stream类全路径为:java.util.stream.Stream
    对Stream的描述,引用其他文章中觉得比较好的介绍:

    Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。
    即Stream的原理:

    这种风格将要处理的元素集合看作一种流, 流在管道中传输, 并且可以在管道的节点上进行处理, 比如筛选, 排序,聚合等。元素流在管道中经过中间操作(intermediate operation)的处理,最后由最终操作(terminal operation)得到前面处理的结果。
    集合有两种方式生成流:
    - stream() − 为集合创建串行流。
    - parallelStream() − 为集合创建并行流。

    并发模式(parallelStream)能够充分利用多核处理器的优势,使用 fork/join 并行方式来拆分任务和加速处理过程。java中也提供了多种并行处理的方式,看到一片文章对各几种并行的方式性能进行了测试,可以参考下:java中几种并行方式的性能分析。

    Stream的的中间操作(intermediate)和最终操作(terminal)都包含哪些方法可以从类结构中看到:


    上面截图基本包含了Strram的所有方法。

    中间操作(intermediate)主要有以下方法(此类型的方法返回的都是Stream对象):
    map (mapToInt, flatMap 等)、 filter、 distinct、 sorted、 peek、 limit、 skip、 parallel、 sequential、 unordered

    终端操作(terminal)主要有以下方法:
    forEach、 forEachOrdered、 toArray、 reduce、 collect、 min、 max、 count、 anyMatch、 allMatch、 noneMatch、 findFirst、 findAny、 iterator

    此处按照类结构(截图)中的方法的顺序(以下例子中使用了Lambda表达式及方法引用,不了解的请戳:Lambda介绍,方法引用),进行介绍:

    filter:通过设置条件来过滤元素。
    List<String> list = Arrays.asList("aaa","ddd","bbb","ccc","a2a","d2d","b2b","c2c","a3a","d3d","b3b","c3c");

    list.stream()
    .filter((s)->s.contains("a"))
    .forEach(s -> System.out.println(s));
    1
    2
    3
    4
    5
    以上代码使用filter方法过滤出只包含”a”的元素,然后通过forEach将满足条件的元素遍历出来。输出如下:

    aaa
    a2a
    a3a
    map:就是将对应的元素使用给定方法进行转换。
    list.stream()
    .filter((s)->s.contains("a"))
    .map((s)-> s + "---map")
    .forEach(s -> System.out.println(s));
    1
    2
    3
    4
    5
    在filter的基础上,给每个元素后面添加字符串”—map”,输出如下:

    aaa—map
    a2a—map
    a3a—map
    mapToInt:和map方法进行一样的操作,但是转换函数必须返回int类型
    mapToLong:和map方法进行一样的操作,但是转换函数必须返回long类型
    mapToDouble:和map方法进行一样的操作,但是转换函数必须返回double类型
    此处以mapToInt进行演示:
    list.stream()
    .filter((s)->s.contains("a"))
    .mapToInt((s)-> s.hashCode())
    .forEach(s -> System.out.println(s));
    1
    2
    3
    4
    在filter的基础上,将每个元素转换为其hashCode。输出为:

    96321
    94864
    94895
    flatMap:如果流的元素为数组或者Collection,flatMap就是将每个Object[]元素或Collection<Object>元素都转换为Object元素,如下:
    Stream<String[]> 转换为 Stream<String>
    Stream<Set> 转换为 Stream<String>
    Stream<List> 转换为 Stream<String>
    Stream<List> 转换为 Stream<Object>
    看下例子:

    List<String[]> setList = new ArrayList<>();
    setList.add(new String[]{"aa","bb"});
    setList.add(new String[]{"cc","dd"});
    setList.add(new String[]{"ee","ff"});
    //使用map方法
    setList.stream()
    .map(s->Arrays.stream(s))
    .forEach(s-> System.out.println("map==" + s));
    //使用flatMap方法
    setList.stream()
    .flatMap(s->Arrays.stream(s))
    .forEach(s-> System.out.println("flatMap==" + s));
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    输出如下:

    map==java.util.stream.ReferencePipeline&Head@50040f0c
    map==java.util.stream.ReferencePipeline&Head@2dda6444
    map==java.util.stream.ReferencePipeline&Head@5e9f23b4
    flatMap==aa
    flatMap==bb
    flatMap==cc
    flatMap==dd
    flatMap==ee
    flatMap==ff
    可以看出map就是将数组流直接返回,flatMap是将数组流中的每个元素都返回。flatMapToInt,flatMapToLong,flatMapToDouble类似,只不过返回的是对应的类型的流,此处不做演示。

    distinct:将集合中的元素去重。
    List<String> disList = Arrays.asList("aaa","ddd","bbb","ddd","aaa");
    disList.stream()
    .distinct()
    .forEach(s-> System.out.println(s));
    1
    2
    3
    4
    输出如下:

    aaa
    ddd
    bbb
    sorted:将集合中的元素排序。
    List<Integer> integerList = Arrays.asList(1,2,3,4);
    integerList.stream()
    .sorted()
    .forEach(s-> System.out.println(s));
    1
    2
    3
    4
    输出如下:

    1
    2
    3
    4
    可以按照自定义排序:

    integerList.stream()
    .sorted((s1,s2)->s2.compareTo(s1))
    .forEach(s-> System.out.println(s));
    1
    2
    3
    输出如下:

    4
    3
    2
    1
    peek:生成一个包含原Stream的所有元素的新Stream,同时会提供一个消费函数即引用的方法A,当Stream每个元素被消费的时候都会先执行新Stream给定的方法A。peek是中间操作,如果pee后没有最终操作,则peek不会执行。
    integerList.stream()
    .peek(s-> System.out.println("peek = "+s));
    1
    2
    此时没有输出,代码改为:

    integerList.stream()
    .peek(s-> System.out.println("peek = "+s))
    .forEach(s-> System.out.println("forEach = "+s));
    1
    2
    3
    输出如下:

    peek = 1
    forEach = 1
    peek = 2
    forEach = 2
    peek = 3
    forEach = 3
    peek = 4
    forEach = 4
    limit:返回Stream的前n个元素。
    integerList.stream()
    .limit(1)
    .forEach(s-> System.out.println(s));
    1
    2
    3
    输出为:

    1
    skip:删除Stream的前n个元素。
    integerList.stream()
    .skip(1)
    .forEach(s-> System.out.println(s));
    1
    2
    3
    输出如下:

    2
    3
    4
    forEach:遍历Stream中的每个元素,前面每个例子都有使用,此处不再演示。
    forEachOrdered:遍历Stream中的每个元素。
    区别:
    在串行流(stream)中没有区别,在并行流(parallelStream)中如果数据源是有序集合,forEachOrdered输出顺序与数据源中顺序一致,forEach则是乱序。
    看下使用forEach:

    integerList.stream()
    .forEach(s-> System.out.println(s));
    1
    2
    输出(多次测试,每次结果都不一样):

    3
    1
    4
    2
    再看使用forEachOrdered:

    integerList.parallelStream()
    .forEachOrdered(s-> System.out.println(s));
    1
    2
    输出(测试多次,每次都是这个结果,与integerList中的元素顺序一致):

    2
    1
    3
    4
    toArray:将流转换为Object[]或者指定类型的数组。
    Object[] array = integerList.stream().toArray();
    String[] strArr = integerList.stream().toArray(String[]::new);
    1
    2
    reduce:将集合中的每个元素聚合成一条数据。有三种情况:
    reduce(BinaryOperator accumulator):此处需要一个参数,返回Optional对象:
    Optional<Integer> reduce = integerList.stream().reduce((a, b) -> a + b);
    1
    reduce(T identity, BinaryOperator accumulator):此处需要两个参数,第一个参数为起始值,第二个参数为引用的方法。从起始值开始,每个元素执行一次引用的方法(方法引用的中的两个参数:第一个参数为上个元素执行方法引用的结果,第二个参数为当前元素)。
    int integer = integerList.stream().reduce(5,(a, b) -> a + b);
    System.out.println(integer);
    1
    2
    输出为:

    15
    此例中使用起始值为5,对集合中每个元素求和,可以理解为:5+2+1+3+4=15。

    reduce(U identity, BiFunction<U, ? super T, U> accumulator, BinaryOperator<U> combiner):此处需要三个参数。此方法用在并发流(parallelStream)中,启动多个子线程使用accumulator进行并行计算,最终使用combiner对子线程结果进行合并,返回identity类型的数据,看到有篇文章对这个解释比较清楚:java8中3个参数的reduce方法怎么理解?
    collect:将流转换成集合或聚合元素。有两种情况。接受一个参数和接受三个参数(三个参数在并发流parallelStream中使用),此处介绍一个参数的情况,单个参数接受的参数类型为Collector,Collectors 类实现了很多归约操作,详见:java8之collector
    List<Integer> collects = integerList.stream()
    .filter(a -> a > 1)
    .collect(Collectors.toList());
    System.out.println(collects);
    1
    2
    3
    4
    此处统计集合中大于1的元素并最终返回list。输出如下:

    [2, 3, 4]
    min:获取集合中最小值。
    Integer min = integerList.stream()
    .filter(a -> a > 1)
    .min((Integer a, Integer b) -> a.compareTo(b))
    .get();
    System.out.println(min);
    1
    2
    3
    4
    5
    输出为:

    2
    max:获取集合中最大值。
    Integer max = integerList.stream()
    .filter(a -> a > 1)
    .max((Integer a, Integer b) -> a.compareTo(b))
    .get();
    System.out.println(max);
    1
    2
    3
    4
    5
    输出为:

    4
    count:获取集合中元素个数
    long count = integerList.stream()
    .filter(a -> a > 1)
    .count();
    System.out.println(count);
    1
    2
    3
    4
    输出为:

    3
    anyMatch: Stream 中任意一个元素符合传入的 predicate,返回 true
    allMatch:Stream 中全部元素符合传入的 predicate,返回 true
    noneMatch:Stream 中没有一个元素符合传入的 predicate,返回 true
    boolean b = integerList.stream()
    .anyMatch(s -> s > 0);
    boolean b1 = integerList.stream()
    .allMatch(s -> s > 0);
    boolean b2 = integerList.stream()
    .noneMatch(s -> s > 0);
    System.out.println("anyMatch = " + b);
    System.out.println("allMatch = " + b1);
    System.out.println("noneMatch = " + b2);
    1
    2
    3
    4
    5
    6
    7
    8
    9
    输出:

    anyMatch = true
    allMatch = true
    noneMatch = false
    findFirst:如果数据源是有序集合,返回Stream 中第一个元素的Optional对象,如果是无序集合,则返回Stream 中任意一个元素的Optional对象。
    Integer first = integerList.stream()
    .findFirst()
    .get();
    System.out.println(first);
    1
    2
    3
    4
    输出为:

    2
    findAny:返回Stream 中任意一个元素的Optional对象。
    Integer any = integerList.stream()
    .findAny()
    .get();
    System.out.println(any);
    1
    2
    3
    4
    输出为:

    2
    Stream还有几个静态方法,返回都是Stream对象。
    静态方法如下:builder(返回Builder对象)、empty、of、iterate、generate、concat。
    builder:返回一个Builder对象,Builder对象在调用build()返回Stream对象。
    empty:返回一个空的有序的Stream对象。
    of:返回包含单个元素的有序的Stream对象。
    iterate:返回一个无限元素的有序的Stream对象。需要两个参数,第一个参数为初始值,第二个参数为要引用的方法,然后会通过递归循环调用引用的方法。

    Stream.iterate(2,s->s+s)
    .limit(10)
    .forEach(s-> System.out.println(s));
    1
    2
    3
    输出为:

    2
    4
    8
    16
    32
    64
    128
    256
    512
    1024
    generate:返回一个无限元素的无序的的Stream对象。需要一个参数,参数为引用的方法,然后会通过循环调用引用的方法来生成元素,常用于生成常量Stream和随机元素Stream。
    concat:将两个Stream连接成一个Stream。需要两个Stream作为参数,如果两个Stream都是有序的并且无论参数Stream是否是并行Stream,得到的都是有序的Stream。输出元素顺序为先输出第一个Stream的元素,然后输出第二个Stream的元素。当结果Stream关闭时候,两个参数Stream同时关闭。

    Stream.concat(integerList.stream(),disList.stream())
    .forEach(s-> System.out.println(s));
    1
    2
    输出为:

    2
    1
    3
    4
    11
    aaa
    ddd
    33
    bbb
    ddd
    aaa
    ————————————————
    版权声明:本文为CSDN博主「昵称2019」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/bluuusea/article/details/79967039

  • 相关阅读:
    Objective-C之NSArray(数组)默认排序与自定义排序
    Objective-C学习笔记之for( int )机制
    OC之NSString、NSMutableString学习笔记 常用方法
    换行回车的区别 2018-10-30
    Python头部2行 #!/usr/bin/python 和 #!/usr/bin/env 的区别 以及编码方式的指定 2018-10-23
    旧版Windows 睡眠与休眠 2018-10-18
    手机尺寸像素 PPI 2018-10-17
    VMvare 虚拟机扩容 2018-10-11
    批量判断网址能否访问 2018-10-04
    字符串的 strip()方法 2018-10-04
  • 原文地址:https://www.cnblogs.com/zhuawang/p/11580750.html
Copyright © 2020-2023  润新知