java8 Collectors.collectingAndThen 常用用法

  

   学习了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的方式去写。再不行,就分两步写。

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天狼1222

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值