java stream api实现mysql的groupby效果
1、需求
实现类似mysql的效果
select name,sex from user group by name,sex
2、实现的思路
目前的stream api的 Collectors.groupingBy可以实现分组的效果,但是返回的结果确实map,key分组的key,vaue为满足key条件的user对象。如果结果只需要name和sex字段。可以把这两个子弹作为key。然后只是保留key。
- sex+name作为key,然后接收key后再拆分
- 直接以新的对象为key,属性包括name和sex。获取后直接输出key就可以 了。
3、代码的实现方式
3.1、对象接收法
定义一个对象,包含分组的key。其实也算输出的List对象
@Test public void groupByTest1() { List<UserBean> userBeanList = createTestList(); List<UserTempBean> result = StreamUtil.groupByField(userBeanList, UserTempBean.class); System.out.println(new Gson().toJson(result)); } public class StreamUtil { public static <T> List<T> groupByField(List list, Class<T> clazz) { Object object = list.stream() .collect( Collectors.groupingBy( item -> { T t = JacksonUtil.parse( JacksonUtil.toJsonString(item), clazz); return t; })); if (null == object) { return null; } HashMap<T, Object> objectHashMap = (HashMap<T, Object>) object; if (null == objectHashMap || objectHashMap.isEmpty()) { return null; } List<T> result = objectHashMap.keySet().stream().collect(Collectors.toList()); return result; }
3.2、见名知意法
- 直接以可变参数的方式实现接口的定义
@Test
public void groupByTest() {
List<UserBean> testList = createTestList();
List<Map<String, Object>> maps = StreamUtil.groupByFileds(testList, "name", "age");
System.out.println(JacksonUtil.toJsonString(maps));
}
public static List<Map<String, Object>> groupByFileds(List list, String... fields) {
Object collect =
list.stream()
.collect(
Collectors.groupingBy(
item -> {
Map parse =
JacksonUtil.parse(
JacksonUtil.toJsonString(item),
Map.class);
if (null == parse || parse.isEmpty()) {
return null;
} else {
Map<String, Object> map = Maps.newHashMap();
for (String field : fields) {
map.put(field, parse.get(field));
}
return map;
}
}));
if (null == collect) {
return null;
}
Map<Map<String, Object>, Object> resultMap = (Map<Map<String, Object>, Object>) collect;
if (null == resultMap || resultMap.isEmpty()) {
return null;
}
return resultMap.keySet().stream().filter(Objects::nonNull).collect(Collectors.toList());
}
4、扩展
- 方法一巧妙的借用了json的序列化和反序列化
- 方法二则是利用json反序列化和map的特性来解决问题
其实还有方式是在方案1的基础上来解决的。利用反射,性能不高,不推荐使用,仅作技术参考
@Test
public void reflecttionGetTest() throws IllegalAccessException {
UserBean userBean = new UserBean("张三", 18, "男");
Object name = ReflectionUtil.getObjectFieldValue(userBean, "name");
System.out.println(name);
Object object = ReflectionUtil.updateObjectField(userBean, "name", "诸葛亮");
System.out.println(JacksonUtil.toJsonString(object));
}
package net.gzcx;
import com.google.common.collect.Lists;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Optional;
/**
* @author chen xing
* @description 反射工具类
* @date 2022-06-23 20:18
*/
public class ReflectionUtil {
/**
* @author chen xing
* @description 设置指定对象的属性值
* @param object
* @param fieldName
* @param fieldValue
* @return void
* @date 2022-06-23 20:21
*/
public static Object updateObjectField(Object object, String fieldName, String fieldValue)
throws IllegalAccessException {
Class objectClass = object.getClass();
Field[] declareFileds = objectClass.getDeclaredFields();
if (null == declareFileds || declareFileds.length == 0) {
return object;
}
for (Field field : declareFileds) {
String name = field.getName();
if (fieldName.equals(name)) {
field.setAccessible(true);
field.set(object, fieldValue);
break;
}
}
return object;
}
/**
* @author chen xing
* @description 获取指定对象的指定的内容
* @param object
* @param fieldName
* @return java.lang.Object
* @date 2022-06-23 20:22
*/
public static Object getObjectFieldValue(Object object, String fieldName)
throws IllegalAccessException {
// 获取对象的class
Class objectClass = object.getClass();
// 初始化该值
Object result = null;
Field[] declaredFields = objectClass.getDeclaredFields();
if (null == declaredFields || declaredFields.length == 0) {
return null;
}
for (Field field : declaredFields) {
String name = field.getName();
if (fieldName.equals(name)) {
field.setAccessible(true);
result = field.get(object);
break;
}
}
return result;
}
}
正文到此结束