java8的优雅-函数式方式实现数据组装挂载-万能数据挂载

374 阅读2分钟

起因

总有一些时刻,给一个List 挂载其他属性(数据组装),每个业务都写,感觉很麻烦,所以来个简单的万能挂载,demo见底部

代码实现

/**
 * 属性挂载
 * <p>
 * Created by songzhaoying on 2021/8/19 16:34.
 *
 * @author songzhaoying@a.com.
 * @date 2021/8/19 16:34.
 */
public class DataMountUtil {

    /**
     * 分组大小
     */
    public static final long LIST_PARTITION_SIZE = 200;

    /**
     * 隐式公有构造
     */
    private DataMountUtil() {

    }

    /**
     * 获取参数
     *
     * @param <T>
     * @param <R>
     * @param bizDatasets
     * @param reqFunction
     * @return
     */
    public static <T, R> R getFinisher(Collection<? extends T> bizDatasets
            , Function<Collection<? extends T>, R> reqFunction) {
        if (CollectionUtils.isEmpty(bizDatasets) || reqFunction == null) {
            return (R) bizDatasets;
        }
        return reqFunction.apply(bizDatasets);
    }

    /**
     * 属性挂载
     *
     * @param bizDatasetsSupplier
     * @param mountDatasetsSupplier
     * @param mountKeyFunction
     * @param mountConsumer
     * @param <T1>
     * @param <T2>
     * @param <K2>
     * @throws Exception
     */
    public static <T1, T2, K2> void beansMountData(Supplier<Collection<? extends T1>> bizDatasetsSupplier
            , Supplier<Collection<? extends T2>> mountDatasetsSupplier
            , Function<? super T2, K2> mountKeyFunction
            , BiConsumer<? super T1, Map<K2, T2>> mountConsumer) throws Exception {

        if (bizDatasetsSupplier == null || mountDatasetsSupplier == null) {
            return;
        }

        beansMountData(bizDatasetsSupplier.get(), mountDatasetsSupplier.get(), mountKeyFunction, mountConsumer);
        return;
    }

    /**
     * 属性挂载
     *
     * @param bizDatasets
     * @param mountDatasetsSupplier
     * @param mountKeyFunction
     * @param mountConsumer
     * @param <T1>
     * @param <T2>
     * @param <K2>
     * @throws Exception
     */
    public static <T1, T2, K2> void beansMountData(final Collection<? extends T1> bizDatasets
            , Supplier<Collection<? extends T2>> mountDatasetsSupplier
            , Function<? super T2, K2> mountKeyFunction
            , BiConsumer<? super T1, Map<K2, T2>> mountConsumer) throws Exception {

        if (mountDatasetsSupplier == null) {
            return;
        }

        beansMountData(bizDatasets, mountDatasetsSupplier.get(), mountKeyFunction, mountConsumer);
        return;
    }


    /**
     * 一对多挂载
     *
     * @param bizDatasetsSupplier
     * @param mountDatasetsSupplier
     * @param mountKeyFunction
     * @param mountConsumer
     * @param <T1>
     * @param <T2>
     * @param <K2>
     * @throws Exception
     */
    public static <T1, T2, K2> void beansMountOne2MoreData(Supplier<Collection<? extends T1>> bizDatasetsSupplier
            , Supplier<Collection<? extends T2>> mountDatasetsSupplier
            , Function<? super T2, K2> mountKeyFunction
            , BiConsumer<? super T1, Map<K2, List<T2>>> mountConsumer) throws Exception {

        if (bizDatasetsSupplier == null || mountDatasetsSupplier == null) {
            return;
        }

        beansMountOne2MoreData(bizDatasetsSupplier.get(), mountDatasetsSupplier.get(), mountKeyFunction, mountConsumer);
        return;
    }

    /**
     * 一对多挂载
     *
     * @param bizDatasets
     * @param mountDatasetsSupplier
     * @param mountKeyFunction
     * @param mountConsumer
     * @param <T1>
     * @param <T2>
     * @param <K2>
     * @throws Exception
     */
    public static <T1, T2, K2> void beansMountOne2MoreData(final Collection<? extends T1> bizDatasets
            , Supplier<Collection<? extends T2>> mountDatasetsSupplier
            , Function<? super T2, K2> mountKeyFunction
            , BiConsumer<? super T1, Map<K2, List<T2>>> mountConsumer) throws Exception {

        if (mountDatasetsSupplier == null) {
            return;
        }

        beansMountOne2MoreData(bizDatasets, mountDatasetsSupplier.get(), mountKeyFunction, mountConsumer);
        return;
    }

    /**
     * 属性挂载
     *
     * @param bizDatasets
     * @param mountDatasets
     * @param mountKeyFunction
     * @param mountConsumer
     * @param <T1>
     * @param <T2>
     * @param <K2>
     * @throws Exception
     */
    public static <T1, T2, K2> void beansMountData(final Collection<? extends T1> bizDatasets
            , final Collection<? extends T2> mountDatasets
            , Function<? super T2, K2> mountKeyFunction
            , BiConsumer<? super T1, Map<K2, T2>> mountConsumer) throws Exception {

        if (CollectionUtils.isEmpty(bizDatasets)
                || CollectionUtils.isEmpty(mountDatasets)
                || mountKeyFunction == null
                || mountConsumer == null) {
            return;
        }

        Map<K2, T2> mountMap = mountDatasets.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toMap(t -> mountKeyFunction.apply(t), Function.identity(), (t1, t2) -> t2));

        // 挂载属性
        bizDatasets.forEach(t -> mountConsumer.accept(t, mountMap));

        return;
    }

    /**
     * 一对多
     *
     * @param bizDatasets
     * @param mountDatasets
     * @param mountKeyFunction
     * @param mountConsumer
     * @param <T1>
     * @param <T2>
     * @param <K2>
     * @throws Exception
     */
    public static <T1, T2, K2> void beansMountOne2MoreData(final Collection<? extends T1> bizDatasets
            , final Collection<? extends T2> mountDatasets
            , Function<? super T2, K2> mountKeyFunction
            , BiConsumer<? super T1, Map<K2, List<T2>>> mountConsumer) throws Exception {

        if (CollectionUtils.isEmpty(bizDatasets)
                || CollectionUtils.isEmpty(mountDatasets)
                || mountKeyFunction == null
                || mountConsumer == null) {
            return;
        }

        Map<K2, List<T2>> mountMoreMap = mountDatasets.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.groupingBy(t -> mountKeyFunction.apply(t)));

        // 挂载属性
        bizDatasets.forEach(t -> mountConsumer.accept(t, mountMoreMap));

        return;
    }

    /**
     * 数据转换处理
     *
     * @param bizDatasets
     * @param itemFunction
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> List<R> extractDataList(Collection<? extends T> bizDatasets
            , Function<? super T, ? extends R> itemFunction) throws Exception {
        if (CollectionUtils.isEmpty(bizDatasets)) {
            return new ArrayList<>(0);
        }
        if (itemFunction == null) {
            if (bizDatasets instanceof List) {
                return (List<R>) bizDatasets;
            }
            return new ArrayList(bizDatasets);
        }
        Function<Collection<? extends T>, List<R>> transFunction = t -> t.stream()
                .filter(Objects::nonNull)
                .map(itemFunction::apply)
                .collect(Collectors.toList());
        return getFinisher(bizDatasets, transFunction);
    }

    /**
     * 数据消费
     *
     * @param bizDatasets
     * @param itemConsumer
     * @param <T>
     * @throws Exception
     */
    public static <T> void consumerDataList(Collection<? extends T> bizDatasets
            , Consumer<? super T> itemConsumer) throws Exception {
        if (CollectionUtils.isEmpty(bizDatasets) || itemConsumer == null) {
            return;
        }

        bizDatasets.forEach(t -> itemConsumer.accept(t));
    }

    /**
     * 数据消费
     *
     * @param bizData
     * @param itemConsumer
     * @param <T>
     * @throws Exception
     */
    public static <T> void consumerData(T bizData, Consumer<? super T> itemConsumer) throws Exception {
        if (bizData == null || itemConsumer == null) {
            return;
        }

        itemConsumer.accept(bizData);
    }

    /**
     * 数据转换处理
     * Function<List<String>, List<ProductFirstDataDetailBusinessDto>> function =
     * t -> productBaseBusinessApi.getBaseProductInfoList(t);
     * Function<List<String>, List<String>> listListFunction =
     * function.andThen(tt -> tt.stream().map(sku -> sku.getOldProductCode()).collect(Collectors.toList()));
     * <p>
     * List<String> stringList = DataMountUtil.extractData(productCodeList, listListFunction);
     *
     * @param bizData
     * @param itemFunction
     * @param <T>
     * @param <R>
     * @return
     */
    public static <T, R> R extractData(T bizData, Function<? super T, ? extends R> itemFunction) throws Exception {
        if (bizData == null || itemFunction == null) {
            return (R) bizData;
        }

        return itemFunction.apply(bizData);
    }

    /**
     * 逐个Function执行
     *
     * @param param     functions[0] 的入参
     * @param functions
     * @param <R>
     * @param <T>
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <R, T> R getCombineFunctionResult(T param, Function... functions) {
        return (R) Stream.of(functions)
                .filter(Objects::nonNull)
                .reduce((current, next) -> current.andThen(next))
                .orElseThrow(() -> new IllegalArgumentException("No functions to combine"))
                .apply(param);
    }


    public static void main(String[] args) throws Exception {
        List<TestPersonBean> testPersonBeanList = Arrays.asList(
                new TestPersonBean(1, "ZhangSan", 1)
                , new TestPersonBean(2, "liSi", 1)
                , new TestPersonBean(3, "LiQin", 2)
        );
        Function<Collection<? extends TestPersonBean>, String> aa = t -> t.stream().map(i -> i.getName()).collect(Collectors.joining(", "));
        String req = getFinisher(testPersonBeanList, aa);
        Function<Collection<? extends TestPersonBean>, List<String>> ab = t -> t.stream().map(i -> i.getName()).collect(Collectors.toList());
        List<String> req1 = getFinisher(testPersonBeanList, ab);
        System.out.println(req);
        System.out.println(req1);

        List<TestSex> testSexList = Arrays.asList(new TestSex(1, "男")
                , new TestSex(2, "女"));

        // 一对一
        beansMountData(testPersonBeanList, () -> testSexList, t -> t.getId()
                , (t, mountDataMap) -> {
                    t.setSexName(mountDataMap.getOrDefault(t.getSex(), new TestSex()).getName());
                });

        System.out.println(testPersonBeanList);

        // 一对多
        beansMountOne2MoreData(testSexList, () -> testPersonBeanList, t -> t.getSex()
                , (t, mountDataMap) -> t.setTestPersonBeanList(mountDataMap.getOrDefault(t.getId(), new ArrayList<>())));

        System.out.println(testSexList);
    }

    /**
     * 测试 bean
     */
    public static class TestPersonBean {
        private Integer id;
        private String name;
        private Integer sex;
        private String sexName;

        public TestPersonBean(Integer id, String name, Integer sex) {
            this.id = id;
            this.name = name;
            this.sex = sex;
        }

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getSex() {
            return sex;
        }

        public void setSex(Integer sex) {
            this.sex = sex;
        }

        public String getSexName() {
            return sexName;
        }

        public void setSexName(String sexName) {
            this.sexName = sexName;
        }
    }

    /**
     * 测试 bean
     */
    public static class TestSex {
        private Integer id;
        private String name;
        private List<TestPersonBean> testPersonBeanList;

        public TestSex() {
        }

        public TestSex(Integer id, String name) {
            this.id = id;
            this.name = name;
        }

        public Integer getId() {
            return id;
        }

        public void setId(Integer id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public List<TestPersonBean> getTestPersonBeanList() {
            return testPersonBeanList;
        }

        public void setTestPersonBeanList(List<TestPersonBean> testPersonBeanList) {
            this.testPersonBeanList = testPersonBeanList;
        }
    }
}