繁体   English   中英

Java8 Stream 分组与 toMap 问题

[英]Java8 Stream grouping by with toMap issue

我有一个名为 ConfigKey 的ConfigKey

public class ConfigKey {
    String code;
    String key;
    String value;
    //omit setter and getter
}

我想将List<ConfigKey>转换为Map<String, Map<String, Object>> ,这是我的方法定义

public Map<String, Map<String, Object> convert (List<ConfigKey> list) {
    return list.stream().collect(Collectors.groupingBy(ConfigKey::getCode, 
            Collectors.toMap(ConfigKey::getKey, ConfigKey::getValue)));
}

但是我想做一些更改,为每个ConfigKey将另一个密钥放入 map,例如

{ "code": "code1","key", "key1", "value": "value1"}
to Map
{"code1": {"key1":"value1", "prefix_key1": "value1" }

有没有 API 像下面这样:

public Map<String, Map<String, Object> convert (List<ConfigKey> list) {
    return list.stream().collect(Collectors.groupingBy(ConfigKey::getCode, 
            Collectors.toMap("prefix_" + ConfigKey::getKey, ConfigKey::getValue))
            Collectors.toMap(ConfigKey::getKey, ConfigKey::getValue)));
}

您可以使用Collector.of()工厂方法,它允许您创建自己的收集器:

public Map<String, Map<String, Object> convert (List<ConfigKey> list) {
    return list.stream().collect(Collectors.groupingBy(ConfigKey::getCode, Collector.of(
        HashMap::new, (m, c) -> {
            m.put(c.getKey(), c.getValue());
            m.put("prefix_" + c.getKey(), c.getValue());
        }, (a, b) -> {
            a.putAll(b);
            return b;
        }
    )));
}

但老实说,这似乎有点混乱,也许一个正常的循环会更好。 流的目的是提供一个 api ,它以更易读的方式做事,但是当你不得不修改这个结构时,通过引入一些非常不可读的逻辑,那么几乎总是更好的选择,只是用的方式来做:

public Map<String, Map<String, Object> convert (List<ConfigKey> list) {
    Map<String, Map<String, Object>> map = new HashMap<>();
    for (ConfigKey ck : list) {
        Map<String, Object> inner = map.computeIfAbsent(ck.getCode(), k -> new HashMap<>());
        inner.put(ck.getKey(), ck.getValue());
        inner.put("prefix_" + ck.getKey(), ck.getValue());
    }
    return map;
}

您可以先将新条目添加到 map,然后将它们分组:

private Map<String, Map<String, Object>> convert(List<ConfigKey> list) {
    new ArrayList<>(list).stream().map(configKey -> new ConfigKey(configKey.getCode(), "prefix_" + configKey.getKey(), configKey.getValue())).forEachOrdered(list::add);
    return list.stream().collect(Collectors.groupingBy(ConfigKey::getCode,
            Collectors.toMap(ConfigKey::getKey, ConfigKey::getValue)));
}

我克隆了列表(为了防止 ConcurrentModificationException),然后将键更改为“新”键(带有映射)并将它们添加到原始列表 - forEachOrdered(list::add)。 由于“代码”字段未更改,因此两个条目都将使用它,从而导致 map 中有 2 个条目

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM