Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a clean (and null safe) way to multiply the values of a map in Java?

I have a Map<String, Double>, and want to multiply all the values in the map by 2, say, but keep the nulls as nulls.

I can obviously use a for loop to do this, but was wondering if there was a cleaner way to do so?

Map<String, Double> someMap = someMapFunction(); Map<String, Double> adjustedMap = new Hashmap<>(); if (someMap != null) {     for (Map.Entry<String,Double> pair : someMap.entryset()) {         if (pair.getValue() == null) {             adjustedMap.put(pair.getKey(), pair.getValue());         } else {             adjustedMap.put(pair.getKey(), pair.getValue()*2)         }      } } 

Also sometimes the map returned by someMapFunction is an immutable map, so this can't be done in place using Map.replaceAll. I couldn't come up with a stream solution that was cleaner.

like image 888
Omar Haque Avatar asked Oct 17 '18 08:10

Omar Haque


People also ask

Can map have multiple null values?

HashMap allows one null key and multiple null values whereas Hashtable doesn't allow any null key or value. HashMap is generally preferred over HashTable if thread synchronization is not needed.

How do you handle null values on a map?

However, if the selectedCert list contains only 2 which are ( AA , BB ), there will be null pointer exception because ccLang is null. Snipped of code: private String ccLang;//Setter and Getter Map<String, String> Cert = new HashMap<String,String>(ss.

IS null allowed in map?

It doesn't allow nulls. So consider using a TreeMap when you want a Map sorts its key-value pairs by the natural order of the keys. Points to remember: Map doesn't allow duplicate keys, but it allows duplicate values.


2 Answers

My first instinct was to suggest a Stream of the input Map's entrySet which maps the values to new values and terminates with collectors.toMap().

Unfortunately, Collectors.toMap throws NullPointerException when the value mapper function returns null. Therefore it doesn't work with the null values of your input Map.

As an alternative, since you can't mutate your input Map, I suggest that you create a copy of it and then call replaceAll:

Map<String, Double> adjustedMap = new HashMap<>(someMap); adjustedMap.replaceAll ((k,v) -> v != null ? 2*v : null); 
like image 189
Eran Avatar answered Sep 20 '22 04:09

Eran


As an alternative to streaming and/or copying solutions, the Maps.transformValues() utility method exists in Google Guava:

Map<String, Double> adjustedMap = Maps.transformValues(someMap, value -> (value != null) ? (2 * value) : null); 

This returns a lazy view of the original map that does not do any work on its own, but applies the given function when needed. This can be both a pro (if you're unlikely to ever need all the values, this will save you some computing time) and a con (if you'll need the same value many times, or if you need to further change someMap without adjustedMap seeing the changes) depending on your usage.

like image 32
Petr Janeček Avatar answered Sep 19 '22 04:09

Petr Janeček