当前位置 > it书童 > java > 正文

流的归约与汇总

java it书童 2021-01-14 16:21:52 0赞 0踩 423阅读 0评论
  • 归约(reduce)将 Stream 流中元素转换成一个值

  • 汇总(collect)将 Stream 流中元素转换成一个容器

java.util.stream.Collectors 已经为我们实现了很多归约与汇总,本质上也是去实现 reduce 或 collect 的接口,如:

以下是自定义实现的汇总和归约,了解下实现流程即可

归约

原理图:

实例:根据一批订单信息,计算平均商品价格

package stream;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Test;

import java.util.ArrayList;

public class ReduceAndCollectTest {

    @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
}

汇总

实例:根据一批订单信息,计算每个用户的平均商品价格

package stream;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.sun.tools.corba.se.idl.constExpr.Or;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.junit.Test;

import java.util.ArrayList;
import java.util.HashMap;

public class ReduceAndCollectTest {

    @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, "one", 2, 25.12));
        list.add(new Order(2, "one", 5, 257.23));
        list.add(new Order(3, "two", 3, 23332.12));

        HashMap<String, Order> collect = list.stream()
            .parallel() // 启用并行计算
            .collect(
                // 定义一个容器
                () -> {
                    System.out.println("执行容器初始化操作");
                    return new HashMap<String, Order>();
                },

                // 将新元素存入集合中
                (HashMap<String, Order> map, Order newOrder) -> {
                    System.out.println("执行新元素添加到容器操作");
                    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 做合并,因为最后 collect 返回的是 map1
                        map1.merge(key, value, (order1, order2) -> {
                            return new Order(0, key, order1.getProductCount() + order2.getProductCount(), order1.getTotalAmount() + order2.getTotalAmount());
                        });
                    });
                }
            );
        System.out.println(JSON.toJSONString(collect, true));
    }

}

结果:

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

Process finished with exit code 0
关于我
一个文科出身的程序员,追求做个有趣的人,传播有价值的知识,微信公众号主要分享读书思考心得,不会有代码类文章,非程序员的同学请放心订阅
转载须注明出处:https://www.itshutong.com/articles/1027