adbdkb
adbdkb

Reputation: 2161

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

I have a utility method defined as below.

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;
}

The String.valueOf(e.getValue()) returns a "null" value from the call. I would like to get the null value for the string.

When I tried the below code, I get an NPE on first .collect call.

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;
}

Upvotes: 0

Views: 1046

Answers (1)

Holger
Holger

Reputation: 298143

The toMap collector doesn’t support null values. But it doesn’t always have to be the 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()));
}

The utility method returns a map with the same keys and transformed values and is flexible enough to allow a recursive application to do the inner map transformation.


Alternatively, we may adapt the solution of this answer to

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)));
}

Unlike the original toMap collector, this won’t throw on duplicate keys, but for this specific case where the input is already a Map, there shouldn’t be duplicate keys anyway.

Upvotes: 1

Related Questions