java strem流

为什么需要 Stream

Stream 作为 Java 8 的一大亮点,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。

  1. JDK1.8引入的新成员,以声明式方式处理集合数据
  2. 将基础操作连接起来,完成复杂的数据处理流水线
  3. 提供透明的并行处理

流与集合的区别

  1. 时间与空间
  2. 只能遍历一次
  3. 外部迭代与内部迭代

对比:原始集合操作与Stream集合操作 (过滤/映射/扁平化/遍历/排序/去重/跳过/截断的应用)

流的组成

流操作的分类

流的使用

原始集合操作与Stream集合操作 (过滤/映射/扁平化/遍历/排序/去重/跳过/截断的应用)

    public static void main(String[] args) {
        List<StreetAlarmReportVo> voList = new ArrayList<>();
        StreetAlarmReportVo vo = null;
        for (int i = 1; i <= 3; i++) {
            vo = new StreetAlarmReportVo();
            vo.setPlaceName("地点" + i);
            vo.setStreetName("南京街");
            vo.setPlaceTypeName("人流量较大的街");
            vo.setFlowNum(i); // 人流量
            vo.setScanNum(i); //扫码人数
            voList.add(vo);
        }
        /**
         * forEach使用:
         * 循环
         */
        voList.stream().forEach(v ->{
            v.setFlowNum(v.getFlowNum() + 1000);
        });
        /**
         *  map使用:
         *  将一个元素转换成另一个元素,创建一个新的集合
         */
        List<String> streetNameList = voList.stream().map(v -> v.getStreetName()).collect(Collectors.toList());
        System.out.println(JSON.toJSONString(streetNameList));

        /**
         * 不用stream流的处理
         */
        List<String> streetStrList = new ArrayList<>();
        for (String streetName : streetNameList){
            streetStrList.add(streetName);
        }
        System.out.println(JSON.toJSONString(streetStrList));

        /**
         * filter使用:
         * 过滤出集合中符合条件的对象
         */
        voList.stream().filter(v -> v.getStreetName().equals("街道1")).forEach(v -> {
            System.out.println(JSON.toJSONString(v));
        });
        List<String> streetList = voList
                .stream().filter(v -> v.getStreetName().equals("街道1"))
                .map(v -> v.getStreetName()).collect(Collectors.toList());
        System.out.println(JSON.toJSONString(streetList));
        /**
         * sorted使用:
         * 顺序排列,加上reversed()方法为倒叙
         */
        voList.stream().sorted(Comparator.comparing(StreetAlarmReportVo::getFlowNum).reversed()).forEach(v -> {
            System.out.println(v.getFlowNum());
        });
        System.out.println(JSON.toJSONString(voList.get(0)));
        /**
         * list排序
         * 顺序排列,加上reversed()方法为倒叙
         * 使用 Comparator.nullsFirst进行排序,当集合中存在null元素时,可以使用针对null友好的比较器,null元素排在集合的最前面
         * 使用 Comparator.thenComparing 排序,首先使用 flowNum 排序,紧接着在使用scanNum 排序
         */
        voList.sort(Comparator.comparing(StreetAlarmReportVo::getFlowNum).reversed());
        System.out.println("顺序排列,加上reversed()方法为倒叙:" + JSON.toJSONString(voList));
        voList.sort(Comparator.nullsFirst(Comparator.comparing(StreetAlarmReportVo::getFlowNum)).reversed());
        System.out.println("使用 Comparator.nullsFirst进行排序:" + JSON.toJSONString(voList));
        voList.sort(Comparator.comparing(StreetAlarmReportVo::getFlowNum).reversed().thenComparing(StreetAlarmReportVo::getScanNum));
        System.out.println("使用 Comparator.thenComparing 排序:" + JSON.toJSONString(voList));
        /**
         * distinct使用:
         * 对流元素进行去重。有状态操作
         */
        List<String> streets = voList.stream().map(v -> v.getStreetName()).distinct().collect(Collectors.toList());
        System.out.println("去重后的元素:" + JSON.toJSONString(streets));
        /**
         * skip使用:
         * 跳过前N条记录,有状态操作
         */
        List<StreetAlarmReportVo> voList2 = voList.stream().skip(2).collect(Collectors.toList());
        System.out.println("使用skip跳过前两条记录:" + JSON.toJSONString(voList2));
        /**
         * limit使用:
         * 截断前N条记录。有状态操作
         */
        List<StreetAlarmReportVo> voList3 = voList.stream().limit(2).collect(Collectors.toList());
        System.out.println("limit截断前2条记录:" + JSON.toJSONString(voList3));
        /**
         * allMatch使用:
         * 终端操作,短路操作。所有元素匹配,返回true
         * anyMatch使用:
         * 任何元素匹配,返回true
         */
        boolean flag = voList.stream().allMatch(v -> v.getStreetName().equals("南京街"));
        boolean flag2 = voList.stream().anyMatch(v -> v.getStreetName().equals("南京街"));
        System.out.println("集合内的街道名称是否都是南京街:" + flag);
        System.out.println("集合内的街道名称是否有一个是南京街:" + flag);
    }

noneMatch使用:任何元素都不匹配,返回true

@Test
    public void noneMatchTest() {
        boolean match = list.stream()

                .peek(sku -> System.out.println(sku.getSkuName()))

                // noneMatch
                .noneMatch(sku -> sku.getTotalPrice() > 10_000);

        System.out.println(match);
    }

findFirst使用:找到第一个

@Test
    public void findFirstTest() {
        Optional<Sku> optional = list.stream()

                .peek(sku -> System.out.println(sku.getSkuName()))

                // findFirst
                .findFirst();

        System.out.println(
                JSON.toJSONString(optional.get(), true));
    }

findAny使用:找任意一个

/**
     * 找任意一个
     */
    @Test
    public void findAnyTest() {
        Optional<Sku> optional = list.stream()

                .peek(sku -> System.out.println(sku.getSkuName()))

                // findAny
                .findAny();

        System.out.println(
                JSON.toJSONString(optional.get(), true));
    }

max使用:找到最大的

@Test
    public void maxTest() {
        OptionalDouble optionalDouble = list.stream()
                // 获取总价
                .mapToDouble(Sku::getTotalPrice)

                .max();

        System.out.println(optionalDouble.getAsDouble());
    }

min使用:找到最小的

@Test
    public void minTest() {
        OptionalDouble optionalDouble = list.stream()
                // 获取总价
                .mapToDouble(Sku::getTotalPrice)

                .min();

        System.out.println(optionalDouble.getAsDouble());
    }

count使用:计数

@Test
    public void countTest() {
        long count = list.stream()
                .count();

        System.out.println(count);
    }
}

流的四种构建形式

由数值直接构建流

@Test
    public void streamFromValue() {
        Stream stream = Stream.of(1, 2, 3, 4, 5);

        stream.forEach(System.out::println);
    }

通过数组构建流

@Test
    public void streamFromArray() {
        int[] numbers = {1, 2, 3, 4, 5};

        IntStream stream = Arrays.stream(numbers);
        stream.forEach(System.out::println);
    }

通过文件生成流

@Test
    public void streamFromFile() throws IOException {
        // TODO 此处替换为本地文件的地址全路径
        String filePath = "";

        Stream<String> stream = Files.lines(
                Paths.get(filePath));

        stream.forEach(System.out::println);
    }

通过函数生成流(无限流)

@Test
    public void streamFromFunction() {
//        2,4,6,8...一直无限下去
//        Stream stream = Stream.iterate(0, n -> n + 2);

        Stream stream = Stream.generate(Math::random);
        stream.limit(100)
                .forEach(System.out::println);

    }

流的预定义收集器

集合收集器

/**
     * 集合收集器
     */
    @Test
    public void toList() {

        List<Sku> list = CartService.getCartSkuList();

        List<Sku> result = list.stream()
                .filter(sku -> sku.getTotalPrice() > 100)

                .collect(Collectors.toList());

        System.out.println(
                JSON.toJSONString(result, true));

    }

分组

@Test
    public void group() {
        List<Sku> list = CartService.getCartSkuList();

        // Map<分组条件,结果集合>
        Map<Object, List<Sku>> group = list.stream()
                .collect(
                        Collectors.groupingBy(
                                sku -> sku.getSkuCategory()));

        System.out.println(
                JSON.toJSONString(group, true));
    }

分区

@Test
    public void partition() {
        List<Sku> list = CartService.getCartSkuList();

        Map<Boolean, List<Sku>> partition = list.stream()
                .collect(Collectors.partitioningBy(
                        sku -> sku.getTotalPrice() > 100));

        System.out.println(
                JSON.toJSONString(partition, true));
    }

分组与分区的区别

归约与汇总操作(涉及到并行执行)

归约reduce

@Test
    public void reduceTest() {

        /**
         * 订单对象
         */
        @Data
        @AllArgsConstructor
        class Order {
            /**
             * 订单编号
             */
            private Integer id;
            /**
             * 商品数量
             */
            private Integer productCount;
            /**
             * 消费总金额
             */
            private Double totalAmount;
        }

        /*
            准备数据
         */
        ArrayList<Order> list = Lists.newArrayList();
        list.add(new Order(1, 2, 25.12));
        list.add(new Order(2, 5, 257.23));
        list.add(new Order(3, 3, 23332.12));

        /*
            以前的方式:
            1. 计算商品数量
            2. 计算消费总金额
         */

        /*
            汇总商品数量和总金额
         */
        Order order = list.stream()
                .parallel()
                .reduce(
                        // 初始化值
                        new Order(0, 0, 0.0),

                        // Stream中两个元素的计算逻辑
                        (Order order1, Order order2) -> {
                            System.out.println("执行 计算逻辑 方法!!!");

                            int productCount =
                                    order1.getProductCount()
                                            + order2.getProductCount();

                            double totalAmount =
                                    order1.getTotalAmount()
                                            + order2.getTotalAmount();

                            return new Order(0, productCount, totalAmount);
                        },

                        // 并行情况下,多个并行结果如何合并
                        (Order order1, Order order2) -> {
                            System.out.println("执行 合并 方法!!!");

                            int productCount =
                                    order1.getProductCount()
                                            + order2.getProductCount();

                            double totalAmount =
                                    order1.getTotalAmount()
                                            + order2.getTotalAmount();

                            return new Order(0, productCount, totalAmount);
                        });

        System.out.println(JSON.toJSONString(order, true));
    }

运行结果

执行 计算逻辑 方法!!!
执行 计算逻辑 方法!!!
执行 计算逻辑 方法!!!
执行 合并 方法!!!
执行 合并 方法!!!
{
    "id":0,
    "productCount":10,
    "totalAmount":23614.469999999998
}

汇总collect

@Test
    public void collectTest() {
        /**
         * 订单对象
         */
        @Data
        @AllArgsConstructor
        class Order {
            /**
             * 订单编号
             */
            private Integer id;
            /**
             * 用户账号
             */
            private String account;
            /**
             * 商品数量
             */
            private Integer productCount;
            /**
             * 消费总金额
             */
            private Double totalAmount;
        }

        /*
            准备数据
         */
        ArrayList<Order> list = Lists.newArrayList();
        list.add(new Order(1, "zhangxiaoxi", 2, 25.12));
        list.add(new Order(2, "zhangxiaoxi",5, 257.23));
        list.add(new Order(3, "lisi",3, 23332.12));

        /*
            Map<用户账号, 订单(数量和金额)>
         */

        Map<String, Order> collect = list.stream()
                .parallel()
                .collect(
                        () -> {
                            System.out.println("执行 初始化容器 操作!!!");

                            return new HashMap<String, Order>();
                        },
                        (HashMap<String, Order> map, Order newOrder) -> {
                            System.out.println("执行 新元素添加到容器 操作!!!");

                            /*
                                新元素的account已经在map中存在了
                                不存在
                             */
                            String account = newOrder.getAccount();

                            // 如果此账号已存在,将新订单数据累加上
                            if (map.containsKey(account)) {
                                Order order = map.get(account);
                                order.setProductCount(
                                        newOrder.getProductCount()
                                                + order.getProductCount());
                                order.setTotalAmount(
                                        newOrder.getTotalAmount()
                                                + order.getTotalAmount());
                            } else {
                                // 如果不存在,直接将新订单存入map
                                map.put(account, newOrder);
                            }

                        }, (HashMap<String, Order> map1, HashMap<String, Order> map2) -> {
                            System.out.println("执行 并行结果合并 操作!!!");

                            map2.forEach((key, value) -> {
                                map1.merge(key, value, (order1, order2) -> {

                                    // TODO 注意:一定要用map1做合并,因为最后collect返回的是map1
                                    return new Order(0, key,
                                            order1.getProductCount()
                                                    + order2.getProductCount(),
                                            order1.getTotalAmount()
                                                    + order2.getTotalAmount());
                                });
                            });
                        });

        System.out.println(JSON.toJSONString(collect, true));
    }

运行结果

执行 初始化容器 操作!!!
执行 初始化容器 操作!!!
执行 初始化容器 操作!!!
执行 新元素添加到容器 操作!!!
执行 新元素添加到容器 操作!!!
执行 新元素添加到容器 操作!!!
执行 并行结果合并 操作!!!
执行 并行结果合并 操作!!!
{
    "lisi":{
        "account":"lisi",
        "id":3,
        "productCount":3,
        "totalAmount":23332.12
    },
    "zhangxiaoxi":{
        "account":"zhangxiaoxi",
        "id":0,
        "productCount":7,
        "totalAmount":282.35
    }
}

猜你喜欢

转载自blog.csdn.net/qq_32526375/article/details/125371949