Java8 Streams - 如何将内部映射的键值从 "null" 字符串修改为空对象

Java8 Streams - How to modify value of keys of inner map to null object from "null" string

我有一个实用方法定义如下。

public static Map<String, Map<String, String>> convertRawMapToStringValues(Map<String, Map<String, Object>> cassandraRowsRawMap) {

    Map<String, Map<String, String>> cassandraStrValuesMap = cassandraRowsRawMap.entrySet()
       .stream()
       .collect(Collectors.toMap(s -> s.getKey(),
          s -> s.getValue().entrySet().stream()
             .collect(Collectors.toMap(e -> e.getKey(), 
                                            e -> String.valueOf(e.getValue())))));
    return cassandraStrValuesMap;
}

String.valueOf(e.getValue()) returns 一个 "null" 值来自调用。我想获取字符串的 null 值。

当我尝试下面的代码时,我在第一次 .collect 调用时得到了一个 NPE。

Map<String, Map<String, String>> cassandraStrValuesMap = cassandraRowsRawMap.entrySet()
   .stream()
   .collect(Collectors.toMap(s -> s.getKey(),
                             s -> s.getValue().entrySet().stream()
                      .collect(Collectors.toMap(e -> e.getKey(), 
                                                e -> e.getValue() == null ? null : String.valueOf(e.getValue())))));
    return cassandraStrValuesMap;
}

toMap 收集器不支持 null 值。但它并不总是必须是 Stream API:

public static <K,T,R> Map<K,R> changeValues(
       Map<? extends K, T> in, Function<? super T, ? extends R> f) {

    Map<K,R> result = new HashMap<>(in.size());
    in.forEach((k,t) -> result.put(k, f.apply(t)));
    return result;
}

public static Map<String, Map<String, String>> convertRawMapToStringValues(
       Map<String, Map<String, Object>> in) {

    return changeValues(in, inner -> changeValues(inner, v -> v==null? null: v.toString()));
}

实用方法 returns 具有相同键和转换值的映射,并且足够灵活以允许递归应用程序进行内部映射转换。


或者,我们可以将 this answer 的解决方案调整为

public static Map<String, Map<String, String>> convertRawMapToStringValues(
       Map<String, Map<String, Object>> in) {

    return in.entrySet().stream()
        .collect(Collectors.toMap(Map.Entry::getKey,
            e -> e.getValue().entrySet().stream()
            .collect(
                HashMap::new,
                (m,e2) -> m.put(e2.getKey(),
                    e2.getValue() == null? null: e2.getValue().toString()),
                Map::putAll)));
}

与最初的 toMap 收集器不同,这不会引发重复键,但对于输入已经是 Map 的特定情况,无论如何都不应该有重复键。