[TOC]
声明
这一系列文章旨在帮助大家理解 Collector
的执行流程,至于实现的是否高效、是否优雅、是否合理等暂且不论。
若对 Collector
的各个流程有疑问请移驾此处:http://blog.csdn.net/hylexus/...
年末了,坑爹的本命年也很快结束了,今天写本命年最后一篇博客:
看着这些名门正派的武功心法(Collectos源码),心底往往会泛起一股淡淡的忧伤,一阶江湖散修的无奈V_V。每每瞄到大派优雅的心法秘诀,内心总会在呐喊:“还有这种操作?”。
不是说看不懂这些大神的实现,只是在没看到人家优雅的实现之前,自己是想不到的V_V。
上次分享的自定义 groupByCollector
实现了分组的功能,但是分组之后的每个分类下都是原来输入的类型。
很多时候,你可能只是需要输入类型的某个属性而已。
比如,分组之后返回的是 Map<Integer, List<User>>
,但是你需要的可能仅仅是user的id,也就是你想要的只是这个: Map<Integer, List<Integer>>
,其中只包含了 user.id
。
现在就来试试实现这个功能,当然此处的实现还是很死板的。很多东西都是写死的。不支持像jdk原生分组功能那样灵活的实现和组合。
简单实现
- 此处还是拿上一篇中的例子来说
static class User {
private Integer id;
private String name;
private Integer gender;
private Integer age;
User(Integer id, String name, Integer gender, Integer age) {
this.id = id;
this.name = name;
this.gender = gender;
this.age = age;
}
// getter,setter
}
List<User> users = Lists.newArrayList(
new User(1, "java", 1, 25),
new User(2, "C", 1, 22),
new User(3, "scala", 0, 23),
new User(4, "C++", 0, 11),
new User(5, "Spark", 1, 25),
new User(6, "PHP", 0, 45),
new User(7, "Python", 1, 89),
new User(8, "JavaScript", 0, 110),
new User(9, "C#", 1, 33)
);
- GroupByCollector
/**
* @param <K> 分组之后的key
* @param <T> 中间转换过程的元素类型
* @param <R> 最终的结果类型
* @author hylexus
*/
static class GroupByCollector3<K, T, R>
implements Collector<T, Map<K, List<T>>, Map<K, List<R>>> {
/**
* 分类器,指定分组之后的key
*/
Function<T, K> classifier;
/**
* 最后一步的转换函数
*/
Function<T, R> finisher;
public GroupByCollector3(Function<T, K> classifier, Function<T, R> finisher) {
this.classifier = classifier;
this.finisher = finisher;
}
@Override
public Supplier<Map<K, List<T>>> supplier() {
return HashMap::new;
}
@Override
public BiConsumer<Map<K, List<T>>, T> accumulator() {
return (map, e) -> {
K key = classifier.apply(e);
List<T> val = Optional.ofNullable(map)
.map(m -> m.get(key))
.orElse(Lists.newArrayList());
val.add(e);
map.put(key, val);
};
}
@Override
public BinaryOperator<Map<K, List<T>>> combiner() {
return (m1, m2) -> {
m2.forEach((k, v) -> {
List<T> val = Optional.ofNullable(m1)
.map(m -> m.get(k))
.orElse(Lists.newArrayList());
val.addAll(v);
});
return m1;
};
}
@Override
public Function<Map<K, List<T>>, Map<K, List<R>>> finisher() {
Function<Map<K, List<T>>, Map<K, List<R>>> function = map -> {
Map<K, List<R>> ret = new HashMap<>();
map.entrySet().stream().forEach(e -> {
List<R> v = e.getValue().stream().map(finisher)
.collect(Collectors.toList());
ret.put(e.getKey(), v);
});
return ret;
};
return function;
}
@Override
public Set<Characteristics> characteristics() {
return Collections.emptySet();
}
}
使用自定义Collector
- 自定义Collector,是获取分组中的userId而非user实例
Map<Integer, List<Integer>> collect = users.stream()
.collect(new GroupByCollector3<>(User::getGender, User::getId));
collect.forEach((k, v) -> {
System.out.println(k);
System.out.println("\t" + v);
});
- 当然,使用jdk内置的实现起来更优雅
Map<Integer, List<Integer>> collect = users.stream()
.collect(
Collectors.groupingBy(
User::getGender,
Collectors.mapping(User::getId, Collectors.toList())
)
);
collect.forEach((k, v) -> {
System.out.println(k);
System.out.println("\t" + v);
});
- 输出效果
0
[3, 4, 6, 8]
1
[1, 2, 5, 7, 9]
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。