Java代码片段工具篇之StreamBinder数据分组简化
【摘要】
什么是分组,在写业务代码时候,经常会遇到分组的需求,将数据根据某一个条件分组成一对多,或者拆分成一对一的关系。JDK是对Stream提供了分组的方法但是不是特别好用,代码写起来也不够精简,为了让业务代码更...
什么是分组,在写业务代码时候,经常会遇到分组的需求,将数据根据某一个条件分组成一对多,或者拆分成一对一的关系。JDK是对Stream提供了分组的方法但是不是特别好用,代码写起来也不够精简,为了让业务代码更加精简,实现业务更简单。对数据分组抽象出一种分组能力。就是StreamBinder。
一、 为什么要精简它
因为记不住这个API,分组就是分组,但是方法是collect()。确实记不住,于是乎就对原始方法进行一个分组。但是遇到一个问题,是自己实现分组,还是使用上面那种分组呢? 通过Stream方法进行分组,在处理大批量数据时候效率会稍微高一点,但是处理几万时间并没有自己实现的效率高。
二、一对多分组
/**
* one to many
* 分组根据相同条件分组
*
* @param dataSourceStream 数据流
* @param <K> key
* @param <T> value
* @return Map
*/
public static <K, T> Map<K, List<T>> group(Stream<T> dataSourceStream,
Function<? super T, ? extends K> keyApply) {
List<T> dataSources = dataSourceStream.collect(Collectors.toList());
Map<K, List<T>> result = new HashMap<>(dataSources.size());
for (T dataSource : dataSources) {
K key = keyApply.apply(dataSource);
List<T> ts = result.get(key);
if (ts == null || ts.isEmpty()) {
ArrayList<T> values = new ArrayList<>();
values.add(dataSource);
result.put(key, values);
} else {
ts.add(dataSource);
}
}
return result;
}
三、一对多分组并重新生成数据
可以看到下面代码是在上面代码的基础上,提供了一个valueApply映射。进行分组之后会在执行valueApply生成新的数据类型
/**
* one to many
* 分组并对分组后的数据进行结构处理,注意出现相同的KEY值,会覆盖
*
* @param dataSourceStream 数据流
* @param keyApply key生成器
* @param valueApply value生成器
* @param <K> key
* @param <V> value
* @param <T> 数据源
* @return Map
*/
public static <K, V, T> Map<K, List<V>> group(Stream<T> dataSourceStream, Function<? super T, ? extends K> keyApply,
Function<? super T, ? extends V> valueApply) {
Map<K, List<T>> beforeGroup = group(dataSourceStream, keyApply);
Map<K, List<V>> afterGroup = new HashMap<>(beforeGroup.size());
for (Map.Entry<K, List<T>> kListEntry : beforeGroup.entrySet()) {
K groupKey = kListEntry.getKey();
List<T> groupValues = kListEntry.getValue();
List<V> collect = groupValues.stream().map(valueApply).collect(Collectors.toList());
afterGroup.put(groupKey, collect);
}
return afterGroup;
}
四、一对一分组
一对一可以叫分组,也可以叫拆分。在项目中我们经常会处理一对一的映射关系。比如根据名字就找到指定的人。既然是一对一映射关系,如果出现了一对多关系就报一个异常 DuplicateFormatFlagsException。
/**
* one to one
* 拆解,将数据拆解成一一对应的关系
*
* @param dataSourceStream 数据流
* @param keyApply key生成器
* @param <K> key
* @param <T> 数据源
* @return Map
*/
public static <K, T> Map<K, T> dismantling(Stream<T> dataSourceStream,
Function<? super T, ? extends K> keyApply) {
return dismantling(dataSourceStream, keyApply, Function.identity());
}
/**
* one to one
* 拆解,将数据拆解成一一对应的关系
*
* @param dataSourceStream 数据流
* @param keyApply key生成器
* @param valueApply value生成器
* @param <K> key
* @param <V> value
* @param <T> 数据源
* @return Map
*/
public static <K, V, T> Map<K, V> dismantling(Stream<T> dataSourceStream, Function<? super T, ? extends K> keyApply,
Function<? super T, ? extends V> valueApply) {
Map<? extends K, List<T>> group = group(dataSourceStream, keyApply);
Map<K, V> result = new HashMap<>(group.size());
for (Map.Entry<? extends K, List<T>> entry : group.entrySet()) {
K key = entry.getKey();
List<T> oldValues = entry.getValue();
if (oldValues == null || oldValues.isEmpty()) {
continue;
}
if (oldValues.size() > 1) {
throw new DuplicateFormatFlagsException(String.format("数据重复,请检查绑定key=%s,value=[%s]", key, oldValues));
}
V newValue = valueApply.apply(oldValues.get(0));
result.put(key, newValue);
}
return result;
}
可能用户想自定义异常,同样提供构造实现
/**
* one to one
* 拆解,将数据拆解成一一对应的关系
*
* @param dataSourceStream 数据流
* @param keyApply key生成器
* @param valueApply value生成器
* @param exceptionSupplier 异常生成
* @param <K> key
* @param <V> value
* @param <T> 数据源
* @param <X> 异常泛型
* @return Map
* @throws X Throwable
*/
public static <K, V, T, X extends Throwable> Map<K, V> dismantling(Stream<T> dataSourceStream,
Function<? super T, ? extends K> keyApply,
Function<? super T, ? extends V> valueApply,
Supplier<? extends X> exceptionSupplier) throws X {
Map<? extends K, List<T>> group = group(dataSourceStream, keyApply);
Map<K, V> result = new HashMap<>(group.size());
for (Map.Entry<? extends K, List<T>> entry : group.entrySet()) {
K key = entry.getKey();
List<T> oldValues = entry.getValue();
if (oldValues == null || oldValues.isEmpty()) {
continue;
}
if (oldValues.size() > 1) {
throw exceptionSupplier.get();
}
V newValue = valueApply.apply(oldValues.get(0));
result.put(key, newValue);
}
return result;
}
五、快速使用
<dependency>
<groupId>com.hanframework</groupId>
<artifactId>common-toolkit</artifactId>
<version>1.0.0-RELEASE</version>
</dependency>
文章来源: springlearn.blog.csdn.net,作者:西魏陶渊明,版权归原作者所有,如需转载,请联系作者。
原文链接:springlearn.blog.csdn.net/article/details/105872507
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)