mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-04-19 03:01:48 +08:00
!583 MapUtil提供change函数,EnumUtil提供getBy函数,通过lambda进行枚举字段映射
Merge pull request !583 from 阿超/v5-dev
This commit is contained in:
commit
e5bc9d5484
@ -2,7 +2,11 @@ package cn.hutool.core.lang.func;
|
|||||||
|
|
||||||
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import cn.hutool.core.lang.SimpleCache;
|
import cn.hutool.core.lang.SimpleCache;
|
||||||
|
import cn.hutool.core.text.CharPool;
|
||||||
|
import cn.hutool.core.text.StrPool;
|
||||||
|
import cn.hutool.core.util.ClassUtil;
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.lang.invoke.SerializedLambda;
|
import java.lang.invoke.SerializedLambda;
|
||||||
@ -53,6 +57,18 @@ public class LambdaUtil {
|
|||||||
return resolve(func).getImplMethodName();
|
return resolve(func).getImplMethodName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取lambda实现类
|
||||||
|
*
|
||||||
|
* @param func lambda
|
||||||
|
* @param <P> 类型
|
||||||
|
* @return lambda实现类
|
||||||
|
*/
|
||||||
|
public static <P> Class<P> getInstantiatedClass(Func1<P, ?> func) {
|
||||||
|
String instantiatedMethodType = resolve(func).getInstantiatedMethodType();
|
||||||
|
return ClassUtil.loadClass(StrUtil.replace(StrUtil.sub(instantiatedMethodType, 2, StrUtil.indexOf(instantiatedMethodType, ';')), StrPool.SLASH, StrPool.DOT));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取lambda表达式函数(方法)名称
|
* 获取lambda表达式函数(方法)名称
|
||||||
*
|
*
|
||||||
@ -65,6 +81,17 @@ public class LambdaUtil {
|
|||||||
return resolve(func).getImplMethodName();
|
return resolve(func).getImplMethodName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取lambda实现类
|
||||||
|
*
|
||||||
|
* @param func lambda
|
||||||
|
* @param <R> 类型
|
||||||
|
* @return lambda实现类
|
||||||
|
*/
|
||||||
|
public static <R> Class<R> getImplClass(Func0<?> func) {
|
||||||
|
return ClassUtil.loadClass(resolve(func).getImplClass().replace(CharPool.SLASH, CharPool.DOT));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取lambda表达式Getter或Setter函数(方法)对应的字段名称,规则如下:
|
* 获取lambda表达式Getter或Setter函数(方法)对应的字段名称,规则如下:
|
||||||
* <ul>
|
* <ul>
|
||||||
|
@ -27,6 +27,8 @@ import java.util.Set;
|
|||||||
import java.util.SortedMap;
|
import java.util.SortedMap;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map相关工具类
|
* Map相关工具类
|
||||||
@ -668,6 +670,25 @@ public class MapUtil {
|
|||||||
return edit(map, t -> filter.accept(t) ? t : null);
|
return edit(map, t -> filter.accept(t) ? t : null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 变更<br>
|
||||||
|
* 变更过程通过传入的 {@link BiFunction} 实现来返回一个值可以为不同类型的 {@link Map}
|
||||||
|
*
|
||||||
|
* @param map 原有的map
|
||||||
|
* @param biFunction {@code lambda},参数包含{@code key},{@code value},返回值会作为新的{@code value}
|
||||||
|
* @param <K> {@code key}的类型
|
||||||
|
* @param <V> {@code value}的类型
|
||||||
|
* @param <R> 新的,修改后的{@code value}的类型
|
||||||
|
* @return 值可以为不同类型的 {@link Map}
|
||||||
|
*/
|
||||||
|
public static <K, V, R> Map<K, R> change(Map<K, V> map, BiFunction<K, V, R> 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保留指定键值对,如果键不存在跳过
|
* 过滤Map保留指定键值对,如果键不存在跳过
|
||||||
*
|
*
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
package cn.hutool.core.util;
|
package cn.hutool.core.util;
|
||||||
|
|
||||||
import cn.hutool.core.lang.Assert;
|
import cn.hutool.core.lang.Assert;
|
||||||
|
import cn.hutool.core.lang.func.Func1;
|
||||||
|
import cn.hutool.core.lang.func.LambdaUtil;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.util.ArrayList;
|
import java.util.*;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.function.Function;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 枚举工具类
|
* 枚举工具类
|
||||||
@ -210,6 +210,35 @@ public class EnumUtil {
|
|||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过 某字段对应值 获取 枚举,获取不到时为 {@code null}
|
||||||
|
*
|
||||||
|
* @param condition 条件字段
|
||||||
|
* @param value 条件字段值
|
||||||
|
* @param <E> 枚举类型
|
||||||
|
* @param <C> 字段类型
|
||||||
|
* @return 对应枚举 ,获取不到时为 {@code null}
|
||||||
|
*/
|
||||||
|
public static <E extends Enum<E>, C> E getBy(Func1<E, C> condition, C value) {
|
||||||
|
return Arrays.stream(LambdaUtil.getInstantiatedClass(condition).getEnumConstants()).filter(e -> condition.callWithRuntimeException(e).equals(value)).findAny().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过 某字段对应值 获取 枚举中另一字段值,获取不到时为 {@code null}
|
||||||
|
*
|
||||||
|
* @param field 你想要获取的字段
|
||||||
|
* @param condition 条件字段
|
||||||
|
* @param value 条件字段值
|
||||||
|
* @param <E> 枚举类型
|
||||||
|
* @param <F> 想要获取的字段类型
|
||||||
|
* @param <C> 条件字段类型
|
||||||
|
* @return 对应枚举中另一字段值 ,获取不到时为 {@code null}
|
||||||
|
*/
|
||||||
|
public static <E extends Enum<E>, F, C> F getFieldBy(Function<E, F> field, Func1<E, C> condition, C value) {
|
||||||
|
return Arrays.stream(LambdaUtil.getInstantiatedClass(condition).getEnumConstants()).filter(e -> condition.callWithRuntimeException(e).equals(value)).findAny().map(field).orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取枚举字符串值和枚举对象的Map对应,使用LinkedHashMap保证有序<br>
|
* 获取枚举字符串值和枚举对象的Map对应,使用LinkedHashMap保证有序<br>
|
||||||
* 结果中键为枚举名,值为枚举对象
|
* 结果中键为枚举名,值为枚举对象
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
package cn.hutool.core.lang.func;
|
package cn.hutool.core.lang.func;
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
public class LambdaUtilTest {
|
public class LambdaUtilTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -18,8 +19,21 @@ public class LambdaUtilTest {
|
|||||||
Assert.assertEquals("age", fieldName);
|
Assert.assertEquals("age", fieldName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getImplClassTest() {
|
||||||
|
// 一般用于封装工具类时减少参数使用
|
||||||
|
Class<MyTeacher> aClass = LambdaUtil.getInstantiatedClass(MyTeacher::getAge);
|
||||||
|
Assert.assertEquals(MyTeacher.class, aClass);
|
||||||
|
|
||||||
|
// 一般用于封装工具类时减少参数使用
|
||||||
|
MyTeacher myTeacher = new MyTeacher();
|
||||||
|
Class<MyTeacher> bClass = LambdaUtil.getImplClass(myTeacher::getAge);
|
||||||
|
Assert.assertEquals(MyTeacher.class, bClass);
|
||||||
|
}
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
static class MyTeacher {
|
static class MyTeacher {
|
||||||
|
|
||||||
public String age;
|
public String age;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,44 @@
|
|||||||
package cn.hutool.core.map;
|
package cn.hutool.core.map;
|
||||||
|
|
||||||
import cn.hutool.core.convert.Convert;
|
import cn.hutool.core.convert.Convert;
|
||||||
|
import cn.hutool.core.lang.Opt;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.Map;
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
public class MapUtilTest {
|
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<User> users;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
public static class UserGroup {
|
||||||
|
private Long userId;
|
||||||
|
private Long groupId;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void filterTest() {
|
public void filterTest() {
|
||||||
Map<String, String> map = MapUtil.newHashMap();
|
Map<String, String> map = MapUtil.newHashMap();
|
||||||
@ -26,6 +55,47 @@ public class MapUtilTest {
|
|||||||
Assert.assertEquals("4", map2.get("d"));
|
Assert.assertEquals("4", map2.get("d"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void changeTest() {
|
||||||
|
// Add test like a foreigner
|
||||||
|
Map<Integer, String> adjectivesMap = MapUtil.<Integer, String>builder()
|
||||||
|
.put(0, "lovely")
|
||||||
|
.put(1, "friendly")
|
||||||
|
.put(2, "happily")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Map<Integer, String> 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<String> customers = new ArrayDeque<>(Arrays.asList("刑部尚书手工耿", "木瓜大盗大漠叔", "竹鼠发烧找华农", "朴实无华朱一旦"));
|
||||||
|
// 分组
|
||||||
|
List<Group> groups = Stream.iterate(0L, i -> ++i).limit(4).map(i -> Group.builder().id(i).build()).collect(Collectors.toList());
|
||||||
|
// 如你所见,它是一个map,key由用户id,value由用户组成
|
||||||
|
Map<Long, User> 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<Long, List<Long>> 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<Long, List<User>> 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<User> 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
|
@Test
|
||||||
public void filterMapWrapperTest() {
|
public void filterMapWrapperTest() {
|
||||||
Map<String, String> map = MapUtil.newHashMap();
|
Map<String, String> map = MapUtil.newHashMap();
|
||||||
|
@ -34,6 +34,20 @@ public class EnumUtilTest {
|
|||||||
Assert.assertTrue(names.contains("name"));
|
Assert.assertTrue(names.contains("name"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getByTest() {
|
||||||
|
// 枚举中字段互相映射使用
|
||||||
|
TestEnum testEnum = EnumUtil.getBy(TestEnum::getType, "type2");
|
||||||
|
Assert.assertEquals("TEST2", testEnum.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void getFieldByTest() {
|
||||||
|
// 枚举中字段互相映射使用
|
||||||
|
String type = EnumUtil.getFieldBy(TestEnum::getType, TestEnum::ordinal, 1);
|
||||||
|
Assert.assertEquals("type2", type);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void likeValueOfTest() {
|
public void likeValueOfTest() {
|
||||||
TestEnum value = EnumUtil.likeValueOf(TestEnum.class, "type2");
|
TestEnum value = EnumUtil.likeValueOf(TestEnum.class, "type2");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user