背景
经常有这种情况,就是获取到一个对象列表之后,需要根据对象里某个字段的值去获取另一个字段的值。如下所示,有个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;
}
}