sunnyone
sunnyone

Reputation: 1530

Best way to map keys of a Map

I want to transform keys in a HashMap. The map has lower_underscore keys but an expected map should have camelCase keys. The map may also have null values.

The straightfoward code to do this is here:

    Map<String, Object> a = new HashMap<String, Object>() {{
        put("foo_bar", 100);
        put("fuga_foga", null); // A value may be null. Collectors.toMap can't handle this value.
    }};
    Map<String, Object> b = new HashMap<>();
    a.forEach((k,v) -> b.put(toCamel(k), v));

I want to know the method to do this like Guava's Maps.transformValues() or Maps.transformEntries(), but these methods just transforms values.

Collectors.toMap() is also close, but this method throws NullPointerException when a null value exists.

    Map<String, Object> collect = a.entrySet().stream().collect(
            Collectors.toMap(x -> toCamel(x.getKey()), Map.Entry::getValue));

Upvotes: 2

Views: 4352

Answers (2)

binoternary
binoternary

Reputation: 1915

This is intended as a comment, but got too long for that.

Wanting something like Guava's Maps.transformValues() or Maps.transformEntries() doesn't make too much sense I think.
Those methods return a view of the original map and when you get some value using a key then the value is transformed by some function that you specified. (I could be wrong here because I'm not familiar with Guava but I'm making these assumptions based on documentation)

If you wanted to do "transform" the keys then you could do it by writing a wapper for the map like so:

public class KeyTransformingMap<K, V> implements Map {
    private Map<K, V> original;
    private Function<K, K> reverseTransformer;

    public V get(Object transformedKey) {
        K originalKey = reverseTransformer.apply((K) transformedKey);
        return original.get(originalKey);
    }

    // delegate all other Map methods directly to original map (or throw UnsupportedOperationException)
}

In your case where you have a map with snake case keys but want camel case keys, the reverseTransformer function would take in a camel case string and return a snake case string.
I.e reverseTransformer.apply("snakeCase") returns "snake_case" which you can then use as a key for the original map.

Having said all that I think that the straightforward code you suggested is the best option.

Upvotes: 1

Modus Tollens
Modus Tollens

Reputation: 5123

If you absolutely want to solve this using streams, you could do it like this:

Map<String, Object> b = a.entrySet()
    .stream()
    .collect(HashMap::new,
            (m, e) -> m.put(toCamel(e.getKey()), e.getValue()),
            HashMap::putAll);

But I find the "conventional" way shown in your question easier to read:

Map<String, Object> b = new HashMap<>();
a.forEach((k,v) -> b.put(toCamel(k), v));

Upvotes: 4

Related Questions