diff --git a/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java b/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java index 63b8c02b7..9cfee1744 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java @@ -27,6 +27,8 @@ import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import java.util.function.BiFunction; /** * Map相关工具类 @@ -548,7 +550,7 @@ public class MapUtil { * @since 5.0.4 */ public static String sortJoin(Map params, String separator, String keyValueSeparator, boolean isIgnoreNull, - String... otherParams) { + String... otherParams) { return join(sort(params), separator, keyValueSeparator, isIgnoreNull, otherParams); } @@ -668,6 +670,25 @@ public class MapUtil { return edit(map, t -> filter.accept(t) ? t : null); } + + /** + * 变更
+ * 变更过程通过传入的 {@link BiFunction} 实现来返回一个值可以为不同类型的 {@link Map} + * + * @param map 原有的map + * @param biFunction {@code lambda},参数包含{@code key},{@code value},返回值会作为新的{@code value} + * @param {@code key}的类型 + * @param {@code value}的类型 + * @param 新的,修改后的{@code value}的类型 + * @return 值可以为不同类型的 {@link Map} + */ + public static Map change(Map map, BiFunction biFunction) { + if (null == map || null == biFunction) { + return MapUtil.newHashMap(); + } + return map.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, m -> biFunction.apply(m.getKey(), m.getValue()))); + } + /** * 过滤Map保留指定键值对,如果键不存在跳过 * diff --git a/hutool-core/src/test/java/cn/hutool/core/map/MapUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/map/MapUtilTest.java index ed47980fe..58ce564a1 100644 --- a/hutool-core/src/test/java/cn/hutool/core/map/MapUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/map/MapUtilTest.java @@ -1,15 +1,44 @@ package cn.hutool.core.map; import cn.hutool.core.convert.Convert; +import cn.hutool.core.lang.Opt; import cn.hutool.core.util.StrUtil; +import lombok.Builder; +import lombok.Data; import org.junit.Assert; import org.junit.Test; -import java.util.HashMap; -import java.util.Map; +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class MapUtilTest { + enum PeopleEnum {GIRL, BOY, CHILD} + + @Data + @Builder + public static class User { + private Long id; + private String name; + } + + @Data + @Builder + public static class Group { + private Long id; + private List users; + } + + @Data + @Builder + public static class UserGroup { + private Long userId; + private Long groupId; + } + + @Test public void filterTest() { Map map = MapUtil.newHashMap(); @@ -26,6 +55,47 @@ public class MapUtilTest { Assert.assertEquals("4", map2.get("d")); } + @Test + public void changeTest() { + // Add test like a foreigner + Map adjectivesMap = MapUtil.builder() + .put(0, "lovely") + .put(1, "friendly") + .put(2, "happily") + .build(); + + Map resultMap = MapUtil.change(adjectivesMap, (k, v) -> v + " " + PeopleEnum.values()[k].name().toLowerCase()); + + Assert.assertEquals("lovely girl", resultMap.get(0)); + Assert.assertEquals("friendly boy", resultMap.get(1)); + Assert.assertEquals("happily child", resultMap.get(2)); + + // 下单用户,Queue表示正在 .排队. 抢我抢不到的二次元周边! + Queue customers = new ArrayDeque<>(Arrays.asList("刑部尚书手工耿", "木瓜大盗大漠叔", "竹鼠发烧找华农", "朴实无华朱一旦")); + // 分组 + List groups = Stream.iterate(0L, i -> ++i).limit(4).map(i -> Group.builder().id(i).build()).collect(Collectors.toList()); + // 如你所见,它是一个map,key由用户id,value由用户组成 + Map idUserMap = Stream.iterate(0L, i -> ++i).limit(4).map(i -> User.builder().id(i).name(customers.poll()).build()).collect(Collectors.toMap(User::getId, Function.identity())); + // 如你所见,它是一个map,key由分组id,value由用户ids组成,典型的多对多关系 + Map> groupIdUserIdsMap = groups.stream().flatMap(group -> idUserMap.keySet().stream().map(userId -> UserGroup.builder().groupId(group.getId()).userId(userId).build())).collect(Collectors.groupingBy(UserGroup::getUserId, Collectors.mapping(UserGroup::getGroupId, Collectors.toList()))); + + // 神奇的魔法发生了, 分组id和用户ids组成的map,竟然变成了订单编号和用户实体集合组成的map + Map> groupIdUserMap = MapUtil.change(groupIdUserIdsMap, (groupId, userIds) -> userIds.stream().map(idUserMap::get).collect(Collectors.toList())); + + // 然后你就可以拿着这个map,去封装groups,使其能够在订单数据带出客户信息啦 + groups.forEach(group -> Opt.ofNullable(group.getId()).map(groupIdUserMap::get).ifPresent(group::setUsers)); + + // 下面是测试报告 + groups.forEach(group -> { + List users = group.getUsers(); + Assert.assertEquals("刑部尚书手工耿", users.get(0).getName()); + Assert.assertEquals("木瓜大盗大漠叔", users.get(1).getName()); + Assert.assertEquals("竹鼠发烧找华农", users.get(2).getName()); + Assert.assertEquals("朴实无华朱一旦", users.get(3).getName()); + }); + // 能写代码真开心 + } + @Test public void filterMapWrapperTest() { Map map = MapUtil.newHashMap();