zoukankan      html  css  js  c++  java
  • 五、流式编程

    流是什么

    Stream(流)是一个来自数据源元素队列并支持聚合操作

    • 元素队列:特定类型的对象形成一个队列。 Java中的Stream并不会存储元素,而是按需计算。
    • 数据源:流的来源。可以是集合,数组,I/O channel, 产生器generator 等。
    • 聚合操作:类似SQL语句一样的操作, 比如filter, map, reduce, find, match, sorted等。

    和以前的Collection操作不同, Stream操作还有两个基础的特征:

    • Pipelining: 中间操作都会返回流对象本身。 这样多个操作可以串联成一个管道, 如同流式风格(fluent style)。 这样做可以对操作进行优化, 比如延迟执行(laziness)和短路( short-circuiting)。
    • 内部迭代:以前对集合遍历都是通过Iterator或者For-Each的方式, 显式的在集合外部进行迭代, 这叫做外部迭代。 Stream提供了内部迭代的方式, 通过访问者模式(Visitor)实现。

    流的组成

    +--------------------+       +------+   +------+   +----+   +--------+
    | stream of elements |-----> |filter|-> |sorted|-> |map |-> |collect |
    +--------------------+       +------+   +------+   +----+   +--------+
    |      数据源         |-----> |            中间操作        |-> |终端操作 |
    +--------------------+       +------+   +------+   +----+   +--------+
    

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

    流操作分类

    1. 中间操作(intermediate operation)
      • 无状态操作
        • 过滤(filter)
        • 映射(map)
        • 扁平化(flatMap)
        • 遍历(peek)
      • 有状态操作
        • 去重(distinct)
        • 跳过(slip)
        • 截断(limit)
        • 排序(sorted)
    2. 终端操作(terminal operation)
      • 非短路操作
        • 遍历(forEach)
        • 归约(reduce)
        • 最大值(max)
        • 最小值(min)
        • 聚合(collect)
        • 计数(count等)
      • 短路操作
        • 所有匹配(allMatch)
        • 任意匹配(anyMatch)
        • 不匹配(noMatch)
        • 查找首个(findFirst)
        • 查找任意(findAny)

    实例

    /**
     * @author fangliu
     * @date 2020-02-13
     * @description 演示流的各种操作
     */
    public class StreamOperatorTest {
        /**
         * 模拟测试数据
         */
        private static List<Goods> goodsList= new ArrayList<Goods>(){
            {
                add(new Goods(111,"无人机", GoodTypeEnum.DIGITAL,10000.00, 10000.00,1));
                add(new Goods(112,"VR一体机", GoodTypeEnum.DIGITAL,13000.00, 13000.00,1));
                add(new Goods(113,"衬衫", GoodTypeEnum.APPAREL,100.00, 300.00,3));
                add(new Goods(114,"牛仔裤", GoodTypeEnum.APPAREL,120.00, 120.00,1));
                add(new Goods(115,"Java编程思想", GoodTypeEnum.BOOKS,80.00, 80.00,1));
                add(new Goods(116,"Java核心技术", GoodTypeEnum.BOOKS,90.00, 90.00,1));
                add(new Goods(117,"算法", GoodTypeEnum.BOOKS,60.00, 60.00,1));
                add(new Goods(118,"跑步机", GoodTypeEnum.SPORTS,3600.00, 3600.00,1));
    
            }
        };
        /**
         * forEach 来迭代流中的每个元素
         */
        @Test
        public void forEachTest(){
            goodsList.stream()
                    .forEach(goods->System.out.println(JSON.toJSONString(goods)));
        }
    
        /**
         * filter 通过设置的条件过滤出元素
         */
        @Test
        public void filterTest(){
            goodsList.stream()
                    // 过滤出商品中的图书类
                    .filter(goods-> GoodTypeEnum.BOOKS.equals(goods.getGoodType()))
                    .forEach(goods->System.out.println(JSON.toJSONString(goods)));
        }
        /**
         * map 映射每个元素到对应的结果
         */
        @Test
        public void mapTest(){
            goodsList.stream()
                    // 将商品中名字映射到结果中
                    .map(goods-> goods.getGoodName())
                    .forEach(goods->System.out.println(JSON.toJSONString(goods,true)));
        }
    
        /**
         * flatMap 将一个对象转换成流
         */
        @Test
        public void flatMapTest(){
            goodsList.stream()
                    // 将商品中名字转换成流
                    .flatMap(goods-> Arrays.stream(goods.getGoodName().split("")))
                    .forEach(goods->System.out.println(JSON.toJSONString(goods,true)));
        }
        /**
         * peek 来迭代流中的每个元素,与forEach相似,但不会销毁流元素
         */
        @Test
        public void peekTest(){
            goodsList.stream()
                    // 迭代商品中的商品名字
                    .peek(goods-> System.out.println(goods.getGoodName()))
                    .forEach(goods->System.out.println(JSON.toJSONString(goods,true)));
        }
    
        /**
         * sorted 对流中的元素进行排序 可选择自然排序或者排序规则
         */
        @Test
        public void sortedTest(){
            goodsList.stream()
                    // 按商品的价格进行排序
                    .sorted(Comparator.comparing(goods -> goods.getGoodPrice()))
                    .forEach(goods->System.out.println(JSON.toJSONString(goods)));
        }
    
        /**
         * distinct 对流中的元素去重
         */
        @Test
        public void distinctTest(){
            goodsList.stream()
                    // 将商品类型映射到结果中
                    .map(goods ->goods.getGoodType())
                    //去重
                    .distinct()
                    .forEach(goods->System.out.println(JSON.toJSONString(goods)));
        }
    
        /**
         * skip 跳过前N条元素
         */
        @Test
        public void skipTest(){
            goodsList.stream()
                    // 按商品的价格进行排序,
                    .sorted(Comparator.comparing(goods -> goods.getGoodPrice()))
                    // 跳过前两条
                    .skip(2)
                    .forEach(goods->System.out.println(JSON.toJSONString(goods)));
        }
    
        /**
         * limit 截断前N条元素
         */
        @Test
        public void limitTest(){
            goodsList.stream()
                    // 按商品的价格进行排序,
                    .sorted(Comparator.comparing(goods -> goods.getGoodPrice()))
                    // 截断前两条
                    .limit(2)
                    .forEach(goods->System.out.println(JSON.toJSONString(goods)));
        }
    
    
        /***********************************************/
    
    
        /**
         *allMatch  必须全部都满足才会返回true
         */
        @Test
        public void allMatchTest(){
            boolean allMatch =goodsList.stream()
                    .peek(goods->System.out.println(JSON.toJSONString(goods)))
                    // 商品单价大于500
                    .allMatch(goods -> goods.getGoodPrice()>500);
            System.out.println(allMatch);
        }
    
    
        /**
         *anyMatch  只要有一个条件满足即返回true
         */
        @Test
        public void anyMatchTest(){
            boolean allMatch =goodsList.stream()
                    .peek(goods->System.out.println(JSON.toJSONString(goods)))
                    // 商品单价大于1000
                    .anyMatch(goods -> goods.getGoodPrice()>1000);
            System.out.println(allMatch);
        }
    
    
        /**
         *noneMatch  全都不满足才会返回true
         */
        @Test
        public void noneMatchTest(){
            boolean allMatch =goodsList.stream()
                    .peek(goods->System.out.println(JSON.toJSONString(goods)))
                    // 商品单价大于10000
                    .noneMatch(goods -> goods.getGoodPrice()>10000);
            System.out.println(allMatch);
        }
    
    
        /**
         *findFirst  找到第一个元素
         */
        @Test
        public void findFirstTest(){
            Optional optional =goodsList.stream()
                    .findFirst();
            System.out.println(JSON.toJSONString(optional.get()));
        }
    
        /**
         *findAny  找到任意一个元素
         */
        @Test
        public void findAnyTest(){
            for (int i = 0; i < 20; i++) {
                Optional optional =goodsList.stream()
                        .findAny();
                System.out.println(JSON.toJSONString(optional.get()));
            }
    
        }
    
        /**
         * mapToInt/mapToLong/mapToDouble  主要用于int、double、long等基本类型上,进行统计结果
         */
        @Test
        public void mapToXXTest(){
            DoubleSummaryStatistics stats = goodsList.stream()
                    // 将商品价格映射到流中
                    .map(goods ->goods.getGoodPrice())
                    .mapToDouble((x)-> x).summaryStatistics();
            System.out.println("商品中价格最贵的商品 : " + stats.getMax());
            System.out.println("商品中价格最便宜的商品 : " + stats.getMin());
            System.out.println("所有商品的价格之和 : " + stats.getSum());
            System.out.println("商品的平均数 : " + stats.getAverage());
        }
    }
    

    流的构建

    1. 由值创建流
    2. 由数组创建流
    3. 由文件创建流
    4. 由函数生产流

    实例

    /**
     * @author fangliu
     * @date 2020-02-14
     * @description 流的四种构建形式
     */
    public class StreamConstructor {
    
        /**
         * 由值创建流
         */
        @Test
        public void streamFromValue(){
            Stream stream = Stream.of(1, 2, 3, 4, 5, 6);
            stream.forEach(System.out::println);
        }
        /**
         * 由数组创建流
         */
        @Test
        public void streamFromArrays(){
            int[] numbers = {1, 2, 3, 4, 5, 6};
            IntStream stream = Arrays.stream(numbers);
            stream.forEach(System.out::println);
        }
        /**
         * 由文件创建流
         */
        @Test
        public void streamFromFiles() throws IOException {
            String path = "/Users/fangliu/data/workspace/study/src/test/java/com/example/demo/stream/StreamConstructor.java";
            Stream stream = Files.lines(Paths.get(path));
            stream.forEach(System.out::println);
        }
        /**
         * 由函数生产流(无限流)
         */
        @Test
        public void streamFromValue1(){
            //Stream stream = Stream.iterate(0,n->n+2);
            Stream stream = Stream.generate(Math::random);
            stream.limit(100).forEach(System.out::println);
        }
    
    }
    

    收集器

    • 将流中的元素累积成一个结果
    • 作用于终端操作的collect()上
    • collect/Collector/Collectors

    预定义收集器功能

    • 将流元素归约
    • 将流元素分组
    • 将流元素分区
    
        /**
         *  collect Collectors类实现了很多归约操作,例如将流转换成集合和聚合元素。Collectors 可用于返回列表或字符串
         */
        @Test
        public void collectTest(){
            // 将商品价格大于1500的转换成商品集合
            List<Goods> list=goodsList.stream()
                    .filter(goods -> goods.getGoodPrice()>1500)
                    .collect(Collectors.toList());
            System.out.println(list);
            
             //将商品名用逗号拼接成字符串
            String str=goodsList.stream()
                    .map(goods -> goods.getGoodName())
                    .collect(Collectors.joining(","));
            System.out.println(str);
    
            // Map<分组条件,结果集合>
            Map<Object,List<Goods>> group=goodsList.stream()
                    //按照商品类型分组
                    .collect(Collectors.groupingBy(goods -> goods.getGoodType()));
            System.out.println(JSON.toJSONString(group,true));
    
            // Map<分区条件,结果集合> 分区是分组的一个特例
            Map<Boolean,List<Goods>> partition=goodsList.stream()
                    //商品大于1000的商品归为true 其余false
                    .collect(Collectors.partitioningBy(goods -> goods.getGoodPrice()>1000));
            System.out.println(JSON.toJSONString(partition,true));
        }
    
  • 相关阅读:
    通过代码获取log4net的文件路径
    关键字后面不加空格
    ASP.NET MVC 4 Content Map
    ASP.NET Overview
    ASP.NET 4 and Visual Studio 2010
    Newtonsoft.Json
    ASP.NET MVC
    log4net
    AutoMapper introduction
    ajax jsonp跨域
  • 原文地址:https://www.cnblogs.com/bigfairy/p/14002071.html
Copyright © 2011-2022 走看看