学习了groupingBy的用法,里面经常会用到 Collectors.collectingAndThen,我理解为后续操作。
JDK源码
java.util.stream.Collectors#collectingAndThen方法的作用是将Collector的结果在执行一个额外的finisher转换操作,其源码如下:
/**
* Adapts a {@code Collector} to perform an additional finishing
* transformation. For example, one could adapt the {@link #toList()}
* collector to always produce an immutable list with:
* <pre>{@code
* List<String> people
* = people.stream().collect(collectingAndThen(toList(), Collections::unmodifiableList));
* }</pre>
*
* @param <T> the type of the input elements
* @param <A> intermediate accumulation type of the downstream collector
* @param <R> result type of the downstream collector
* @param <RR> result type of the resulting collector
* @param downstream a collector
* @param finisher a function to be applied to the final result of the downstream collector
* @return a collector which performs the action of the downstream collector,
* followed by an additional finishing step
*/
public static<T, A, R, RR> Collector<T, A, RR> collectingAndThen(Collector<T, A, R> downstream, Function<R, RR> finisher) {
Set<Collector.Characteristics> characteristics = downstream.characteristics();
if (characteristics.contains(Collector.Characteristics.IDENTITY_FINISH)) {
if (characteristics.size() == 1) {
characteristics = Collectors.CH_NOID;
} else {
characteristics = EnumSet.copyOf(characteristics);
characteristics.remove(Collector.Characteristics.IDENTITY_FINISH);
characteristics = Collections.unmodifiableSet(characteristics);
}
}
return new CollectorImpl<>(downstream.supplier(),
downstream.accumulator(),
downstream.combiner(),
downstream.finisher().andThen(finisher),
characteristics);
}
T:输入元素的类型
A:下游Collector的中间堆积类型
R:下游Collector的结果类型
RR:结果Collector的结果类型
参数:此方法接受下面列出的两个参数
downstream: Collector的一个实例,可以使用任何Collector
finisher: 类型是Function,该函数将应用于下游Collector的最终结果
返回值:返回一个执行下游Collector动作的Collector,然后在finisher函数的帮助下执行附加的转换步骤。
使用:
模拟数据:
public static JSONArray initData(){
String data = "[{\"code\":\"4\",\"codeType\":\"ALRAM\",\"sortId\":\"4\",\"name\":\"特级告警\"},{\"code\":\"2\",\"codeType\":\"ALRAM\",\"sortId\":\"2\",\"name\":\"中级告警\"},{\"code\":\"3\",\"codeType\":\"ALRAM\",\"sortId\":\"3\",\"name\":\"严重告警\"},{\"code\":\"1\",\"codeType\":\"ALRAM\",\"sortId\":\"1\",\"name\":\"普通告警\"},{\"code\":\"2\",\"codeType\":\"NOTICE\",\"sortId\":\"2\",\"name\":\"邮箱通知\"},{\"code\":\"1\",\"codeType\":\"NOTICE\",\"sortId\":\"1\",\"name\":\"短信通知\"},{\"code\":\"3\",\"codeType\":\"NOTICE\",\"sortId\":\"3\",\"name\":\"微信消息通知\"}]";
return JSON.parseArray(data);
}
toList
获取字段类型的各名称
public static void main(String[] args){
JSONArray items = initData();
Map<String, List<String>> codeTypeNameMap1 = ListUtils.emptyIfNull(items).stream().map(e -> (JSONObject) e)
.collect(Collectors.groupingBy(e -> MapUtils.getString(e, "codeType"), Collectors
.collectingAndThen(Collectors.toList(),
t -> ListUtils.emptyIfNull(t).stream().map(x -> MapUtils.getString(x, "name"))
.filter(Objects::nonNull).distinct().collect(Collectors.toList()))));
System.out.println(JSON.toJSONString(codeTypeNameMap1));
}
结果:
{
"NOTICE": ["邮箱通知", "短信通知", "微信消息通知"],
"ALRAM": ["特级告警", "中级告警", "严重告警", "普通告警"]
}
不过这种写法会有点繁琐,使用mapping更为简便直观:
Map<String, List<String>> codeTypeNameMap2 = ListUtils.emptyIfNull(items).stream().map(e -> (JSONObject) e)
.collect(Collectors.groupingBy(e -> MapUtils.getString(e, "codeType"),
Collectors.mapping(f1 -> MapUtils.getString(f1, "name"), Collectors.toList())));
System.out.println(JSON.toJSONString(codeTypeNameMap2));
toMap
获取字段类型的字典及其名称
public static void main(String[] args){
JSONArray items = initData();
Map<String, Map<String, String>> codeTypeMap1 = ListUtils.emptyIfNull(items).stream().map(e -> (JSONObject) e)
.collect(Collectors.groupingBy(e -> MapUtils.getString(e, "codeType"),
Collectors.collectingAndThen(Collectors.toMap(f1 -> MapUtils.getString(f1, "code"),
f2 -> MapUtils.getString(f2, "name"), (x, y) -> x), v -> v)));
System.out.println(JSON.toJSONString(codeTypeMap1));
}
结果:
{
"NOTICE": {
"1": "短信通知",
"2": "邮箱通知",
"3": "微信消息通知"
},
"ALRAM": {
"1": "普通告警",
"2": "中级告警",
"3": "严重告警",
"4": "特级告警"
}
}
这个直接用toMap的方式也更为简便直观
Map<String, Map<String, String>> codeTypeMap2 = ListUtils.emptyIfNull(items).stream().map(e -> (JSONObject) e)
.collect(Collectors.groupingBy(e -> MapUtils.getString(e, "codeType"),
Collectors.toMap(f1 -> MapUtils.getString(f1, "code"),
f2 -> MapUtils.getString(f2, "name"), (x, y) -> x)));
System.out.println(JSON.toJSONString(codeTypeMap2));
maxBy
分组后找到code最大的内容
public static void main(String[] args){
JSONArray items = initData();
Map<String, JSONObject> codeMax = ListUtils.emptyIfNull(items).stream().map(e -> (JSONObject) e)
.collect(Collectors.groupingBy(e -> MapUtils.getString(e, "codeType"),
Collectors.collectingAndThen(Collectors.maxBy(Comparator.comparingInt(f1 -> MapUtils.getInteger(f1, "code"))), Optional::get)));
System.out.println(JSON.toJSONString(codeMax));
}
结果:
{
"NOTICE": {
"code": "3",
"codeType": "NOTICE",
"sortId": "3",
"name": "微信消息通知"
},
"ALRAM": {
"code": "4",
"codeType": "ALRAM",
"sortId": "4",
"name": "特级告警"
}
}
这个可以直接用toMap和BinaryOperator.maxBy进行处理
public static void main(String[] args){
JSONArray items = initData();
Map<String, JSONObject> codeMax = ListUtils.emptyIfNull(items).stream().map(e -> (JSONObject) e)
.collect(Collectors.toMap(e -> MapUtils.getString(e, "codeType"),
Function.identity(),
BinaryOperator.maxBy(Comparator.comparingInt(f1 -> MapUtils.getInteger(f1, "code")))));
System.out.println(JSON.toJSONString(codeMax));
}
sort asc
分组后,根据sortId进行排序-正序
public static void main(String[] args){
JSONArray items = initData();
Map<String, List<JSONObject>> groupAscSort = ListUtils.emptyIfNull(items).stream()
.map(e -> (JSONObject) e)
.collect(Collectors.groupingBy(e -> MapUtils.getString(e, "codeType"),
LinkedHashMap::new,
Collectors.collectingAndThen(Collectors.toList(), s ->
s.stream().sorted(Comparator.comparing(e -> e.getInteger("sortId"))).collect(Collectors.toList()))));
System.out.println(JSON.toJSONString(groupAscSort));
}
结果:
{
"ALRAM": [{
"code": "1",
"codeType": "ALRAM",
"sortId": "1",
"name": "普通告警"
}, {
"code": "2",
"codeType": "ALRAM",
"sortId": "2",
"name": "中级告警"
}, {
"code": "3",
"codeType": "ALRAM",
"sortId": "3",
"name": "严重告警"
}, {
"code": "4",
"codeType": "ALRAM",
"sortId": "4",
"name": "特级告警"
}],
"NOTICE": [{
"code": "1",
"codeType": "NOTICE",
"sortId": "1",
"name": "短信通知"
}, {
"code": "2",
"codeType": "NOTICE",
"sortId": "2",
"name": "邮箱通知"
}, {
"code": "3",
"codeType": "NOTICE",
"sortId": "3",
"name": "微信消息通知"
}]
}
sort desc
分组后,根据sortId进行排序-反序
public static void main(String[] args){
JSONArray items = initData();
Map<String, List<JSONObject>> groupReverseSort = ListUtils.emptyIfNull(items).stream()
.map(e -> (JSONObject) e)
.collect(Collectors.groupingBy(e -> MapUtils.getString(e, "codeType"),
LinkedHashMap::new,
Collectors.collectingAndThen(Collectors.toList(), s ->
s.stream().sorted((c1, c2) ->
MapUtils.getInteger(c2, "sortId").compareTo(MapUtils.getInteger(c1, "sortId"))).collect(Collectors.toList()))));
System.out.println(JSON.toJSONString(groupReverseSort));
}
结果:
{
"ALRAM": [{
"code": "4",
"codeType": "ALRAM",
"sortId": "4",
"name": "特级告警"
}, {
"code": "3",
"codeType": "ALRAM",
"sortId": "3",
"name": "严重告警"
}, {
"code": "2",
"codeType": "ALRAM",
"sortId": "2",
"name": "中级告警"
}, {
"code": "1",
"codeType": "ALRAM",
"sortId": "1",
"name": "普通告警"
}],
"NOTICE": [{
"code": "3",
"codeType": "NOTICE",
"sortId": "3",
"name": "微信消息通知"
}, {
"code": "2",
"codeType": "NOTICE",
"sortId": "2",
"name": "邮箱通知"
}, {
"code": "1",
"codeType": "NOTICE",
"sortId": "1",
"name": "短信通知"
}]
}
总结:
Collectors.collectingAndThen除了排序的,另外其它都直接替换。但是也要熟悉,这样当遇到需要进一步处理数据,也不知道有更简便的方法的时候,就可以直接用 collectingAndThen的方式去写。再不行,就分两步写。