javahashmapjava-8java-stream

Lowercase all HashMap keys


I 've run into a scenario where I want to lowercase all the keys of a HashMap (don't ask why, I just have to do this). The HashMap has some millions of entries.

At first, I thought I 'd just create a new Map, iterate over the entries of the map that is to be lowercased, and add the respective values. This task should run only once per day or something like that, so I thought I could bare this.

Map<String, Long> lowerCaseMap = new HashMap<>(myMap.size());
for (Map.Entry<String, Long> entry : myMap.entrySet()) {
   lowerCaseMap.put(entry.getKey().toLowerCase(), entry.getValue());
}

this, however, caused some OutOfMemory errors when my server was overloaded during this one time that I was about to copy the Map.

Now my question is, how can I accomplish this task with the smallest memory footprint?

Would removing each key after lowercased - added to the new Map help?

Could I utilize java8 streams to make this faster? (e.g something like this)

Map<String, Long> lowerCaseMap = myMap.entrySet().parallelStream().collect(Collectors.toMap(entry -> entry.getKey().toLowerCase(), Map.Entry::getValue));

Update It seems that it's a Collections.unmodifiableMap so I don't have the option of

removing each key after lowercased - added to the new Map


Solution

  • Instead of using HashMap, you could try using a TreeMap with case-insensitive ordering. This would avoid the need to create a lower-case version of each key:

    Map<String, Long> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
    map.putAll(myMap);
    

    String.CASE_INSENSITIVE_ORDER is a Comparator that does case-insensitive comparisons of strings. Once you've constructed this map, put() and get() will behave case-insensitively, so you can save and fetch values using all-lowercase keys. Iterating over keys will return them in their original, possibly upper-case forms.

    Here are some similar questions: