Java对象列表属性映射工具类

背景

经常有这种情况,就是获取到一个对象列表之后,需要根据对象里某个字段的值去获取另一个字段的值。如下所示,有个Item对象列表,Item对象里有个id字段和Value字段,现需要根据id的值去查询value的值。

java 复制代码
        // 测试数据
        List<Item> items = Arrays.asList(
                new Item("1", "Item1"),
                new Item("2", "Item2"),
                new Item("3", "Item3")
        );
java 复制代码
    @Data
    static class Item {
        private final String id;
        private final String name;
        private String value;

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

    @Data
    static class Value {
        private String id;
        private String value;

        public Value(String id, String value) {
            this.id = id;
            this.value = value;
        }
    }

实现

常规写法

如下:

java 复制代码
        // 先将id取出来
        List<String> ids = items.stream().map(Item::getId).collect(Collectors.toList());
        // 根据id获取value
        Map<String, Value> valueMap = getValueMap(ids);
        // 遍历items,设置value
        items.stream().forEach(item -> {
            String id = item.getId();
            Value value = valueMap.get(id);
            if (Objects.nonNull(value)) {
                item.setValue(value.getValue());
            }
        });

使用工具类

写法如下:

java 复制代码
        Collection<Item> res = keyValueMapping(
                items,
                Item::getId,
                keys -> getValueList(keys),
                Value::getId,
                (item, values) -> item.setValue(values.get(0).getValue()),
                false
        );

    // 模拟工具id获取value
    public static List<Value> getValueList(List<String> ids) {
        List<Value> values = Lists.newArrayList();
        for (String id : ids) {
            values.add(new Value(id, "Value" + id));
        }
        values.remove(2);
        return values;
    }

工具类代码

java 复制代码
public class FieldMappingUtil {
    private FieldMappingUtil() {
    }

    public static <T, K, V> void keyValueMapping(Collection<T> list, Function<T, K> getKey,
                                                 Function<List<K>, List<V>> key2Values,
                                                 Function<V, K> valueGroup,
                                                 BiConsumer<T, List<V>> setGroupedValues) {
        keyValueMapping(list, getKey, key2Values, valueGroup, setGroupedValues, false);
    }

    public static <T, K, V> void keyValueMapping(Collection<T> list, Function<T, K> getKey,
                                                 Function<List<K>, List<V>> key2Values,
                                                 Function<V, K> valueGroup,
                                                 BiConsumer<T, List<V>> setGroupedValues,
                                                 Consumer<Collection<T>> unmappedData) {
        boolean returnUnmappedData = Objects.nonNull(unmappedData);
        Collection<T> unmapped = keyValueMapping(list, getKey, key2Values,
                valueGroup, setGroupedValues, returnUnmappedData);
        if (returnUnmappedData && CollUtil.isNotEmpty(unmapped)) {
            unmappedData.accept(unmapped);
        }
    }

    public static <T, K, V, R> R keyValueMappingReturn(Collection<T> list,
                                                       Function<T, K> getKey,
                                                       Function<List<K>, List<V>> key2Values,
                                                       Function<V, K> valueGroup,
                                                       BiConsumer<T, List<V>> setGroupedValues,
                                                       Function<Collection<T>, R> unmappedData) {
        boolean returnUnmappedData = Objects.nonNull(unmappedData);
        Collection<T> unmapped = keyValueMapping(list, getKey, key2Values,
                valueGroup, setGroupedValues, returnUnmappedData);
        if (returnUnmappedData && CollUtil.isNotEmpty(unmapped)) {
            return unmappedData.apply(unmapped);
        }
        return null;
    }


    private static <T, K, V> Collection<T> keyValueMapping(Collection<T> list,
                                                           Function<T, K> getKey,
                                                           Function<List<K>, List<V>> key2Values,
                                                           Function<V, K> valueGroup,
                                                           BiConsumer<T, List<V>> setGroupedValues,
                                                           boolean returnUnmappedData) {
        if (CollUtil.isNotEmpty(list)) {
            // 源数据中非空的key
            List<K> nonNullKeys = list.stream().map(getKey).filter(Objects::nonNull).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(nonNullKeys)) {
                // 根据源数据获取目标数据
                List<V> allValues = key2Values.apply(nonNullKeys);
                if (CollUtil.isNotEmpty(allValues)) {
                    // 目标数据按照key分组
                    Map<K, List<V>> map = allValues.stream().collect(Collectors.groupingBy(valueGroup));
                    // 遍历源数据,设置分组后的目标值
                    return list.stream().filter(t -> {
                        // 获取当前对象key
                        K key = getKey.apply(t);
                        // 根据key获取目标数据
                        List<V> values = map.get(key);
                        if (CollUtil.isNotEmpty(values)) {
                            // 设置目标值到当前对象
                            setGroupedValues.accept(t, values);
                            return true;
                        } else {
                            return returnUnmappedData;
                        }
                    }).collect(Collectors.toList());
                }
            }
        }
        return returnUnmappedData ? list : null;
    }
}
相关推荐
JavaEdge.2 分钟前
IDEA卡死没反应的全部解决方案
java·ide·intellij-idea
高山上有一只小老虎8 分钟前
使用Memory Analyzer (MAT)分析内存溢出
java·jvm
嘴贱欠吻!19 分钟前
JavaSE基础知识
java·开发语言
逝水如流年轻往返染尘26 分钟前
Java输入输出
java·开发语言
Alsn8628 分钟前
29.Java中常见加解密算法的基本实现
java·开发语言·算法
沉默王二28 分钟前
TRAE+Gemini,成为我解读 Agent 微服项目的最佳工具
java·后端·程序员
多则惑少则明29 分钟前
SpringBoot3整合knife4j(swagger3)
java·spring boot·swagger
星月昭铭29 分钟前
Spring Boot写一个/v1/chat/completions接口给Cherry Studio流式调用
java·spring boot·后端·ai
独自破碎E30 分钟前
什么是Java的多态特性?
java·开发语言
ss27332 分钟前
自定义线程池:从工作原理到实战验证
java·开发语言·jvm