JAVA 17中List按照组合键分组

概述


之前给公司的供应链同事开发了一个通过管理后台下单的功能,他们会把订单数据放到excel里,然后导入到管理后台,就能给门店下单了。

但是当时上线时,没有做校验excel里是否有重复记录的功能,导致一不小心,就会重复下单。

使用JAVA的分组功能校验重复数据


由于给门店下单的数量不多,一般不会超过500单,因此不需要分批处理,就直接一次性处理即可。

那么怎样算是重复的订单?

门店 + 物料 + 到货日期

只要这三个字段是一样的记录,就认为是重复的,必须提醒操作人,excel有重复记录。

在JAVA的List里,如果想对List里的对象的【多个字段 】进行分组,可以采用Function来自定义一个组合键:

java 复制代码
Function<Order, String> compositeKey = order -> String.format("%s_%s",
        order.getShopName(),order.getMaterialName(),order.getArrivalDay());

定义好这个组合键后,就可以传入到Collectors.groupingBy()方法里,让List按照组合键进行分组。

java 复制代码
        Map<String, Long> groupByOrderKeyMap = orderList.stream().collect(Collectors.groupingBy(compositeKey,Collectors.counting()));

一旦有重复的记录,就抛出异常,提示操作人记录重复了。

java 复制代码
  groupByOrderKeyMap.entrySet().stream()
                .filter(entry -> entry.getValue() > 1)
                .findFirst()
                .ifPresent(entry -> {
                    String [] keyArray = entry.getKey().split("_");
                    String msg = "表格里有重复记录:"+keyArray[0]+","+keyArray[1];
                    throw new RuntimeException(msg);
                });

更优雅的方式


上面的代码里,是使用String.format()方法,将对象的多个字段拼接起来,作为组合key的,这样在解析组合key的时候,就需要使用split()方法进行切割,不太优雅。

其实可以在Order对象里创建一个构造方法,传入门店、物料以及到货日期,然后把整个对象作为组合key的。

java 复制代码
@Data
public class Order {
    private String arrivalDay;
    private String materialName;
    private String shopName;


    public Order(String shopName, String materialName, String arrivalDay) {
        this.arrivalDay = arrivalDay;
        this.materialName = materialName;
        this.shopName = shopName;
    }

   @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Order order = (Order) o;
        return Objects.equals(arrivalDay, order.arrivalDay) &&
               Objects.equals(materialName, order.materialName) &&
               Objects.equals(shopName, order.shopName);
    }

    @Override
    public int hashCode() {
        return Objects.hash(arrivalDay, materialName, shopName);
    }
}

重写equalshashCode方法后,就可以使用如下代码进行分组了。

java 复制代码
Map<Order, Long> groupByOrderKeyMap = orders.stream()
            .collect(Collectors.groupingBy(o -> new Order(o.getShopName(), o.getMaterialName(), o.getArrivalDay()),Collectors.counting()));

这样获取组合key的时候,拿到就是一个Order对象,可以非常方便的获取到对象的字段值。

java 复制代码
  groupByOrderKeyMap.entrySet().stream()
                .filter(entry -> entry.getValue() > 1)
                .findFirst()
                .ifPresent(entry -> {
                    String msg = "表格里有重复记录:"+entry.getShopName()+","+entry.getMaterialName();
                    throw new RuntimeException(msg);
                });

如果想把所有重复的记录都找出来,怎么做?


上面的代码是,只要有一条记录出现重复了,就立刻抛出异常。操作人处理完后,可能还有重复记录他不知道,就又得处理一次甚至多次。

最好能一次性告知操作人,excel里有哪些记录重复了,这样操作人就可以一次性处理掉。代码如下:

java 复制代码
Function<Order, String> compositeKey = order -> String.format("%s_%s",
        order.getShopName(),order.getMaterialName(),order.getArrivalDay());
        
Map<String, List<Order> groupByOrderKeyMap = orderList.stream().collect(Collectors.groupingBy(compositeKey,Collectors.toList()));

输出所有重复的记录

java 复制代码
groupByOrderKeyMap.values().stream()  
                .filter(list -> list.size() > 1)  
                .forEach(duplicates -> {  
                    duplicates.forEach(order -> System.out.println(order));  
                });  
      
相关推荐
zjw_rp6 分钟前
Spring-AOP
java·后端·spring·spring-aop
Oneforlove_twoforjob19 分钟前
【Java基础面试题033】Java泛型的作用是什么?
java·开发语言
TodoCoder27 分钟前
【编程思想】CopyOnWrite是如何解决高并发场景中的读写瓶颈?
java·后端·面试
向宇it36 分钟前
【从零开始入门unity游戏开发之——C#篇24】C#面向对象继承——万物之父(object)、装箱和拆箱、sealed 密封类
java·开发语言·unity·c#·游戏引擎
小蜗牛慢慢爬行38 分钟前
Hibernate、JPA、Spring DATA JPA、Hibernate 代理和架构
java·架构·hibernate
星河梦瑾1 小时前
SpringBoot相关漏洞学习资料
java·经验分享·spring boot·安全
黄名富2 小时前
Redis 附加功能(二)— 自动过期、流水线与事务及Lua脚本
java·数据库·redis·lua
love静思冥想2 小时前
JMeter 使用详解
java·jmeter
言、雲2 小时前
从tryLock()源码来出发,解析Redisson的重试机制和看门狗机制
java·开发语言·数据库
TT哇2 小时前
【数据结构练习题】链表与LinkedList
java·数据结构·链表