What if I don't want Collectors#toMap to throw on null values? Java 8
public class CollectorsTest {
@Test
public void collectorsTest() {
List<Map.Entry<String, Object>> params = Arrays.asList(
new AbstractMap.SimpleEntry<>("key1", 1),
new AbstractMap.SimpleEntry<>("key2", null)
);
Map<String, Object> paramMap = toParamMap(params); // throws NPE
}
private static Map<String, Object> toParamMap(List<Map.Entry<String, Object>> params) {
Map<String, Object> paramMap = params.stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return paramMap;
}
}
The toMap collectors don't permit null entry or values. To avoid this you could use forEach with HashMap.put as in Hiro Silva's answer.
It is also easy to keep using streams, which might be preferred if making use of parallel or filters on the data. A collector based on HashMap will permit use of both null keys and values. Stream.collect handles definition of custom collectors, setting up with arguments to supply a new HashMap and to add entries to that hashmap:
private static Map<String, Object> toParamMap(List<Map.Entry<String, Object>> params) {
return params.stream()
.collect(HashMap::new,
(map, entry) -> map.put(entry.getKey(), entry.getValue()),
HashMap::putAll);
}
It is cumbersome to write the above each time you might need it, but it can be re-worked to new method returning your own hashmap collector with generic key + value types. This works for handling any collections of Map.Entry using Collector.of:
public static <K,V> Collector<Map.Entry<K, V>, Map<K, V>, Map<K, V>> toHashMap() {
return Collector.of(HashMap::new,
(map, entry) -> map.put(entry.getKey(), entry.getValue()),
(a,b) -> { a.putAll(b); return a; });
}
Then you can collect streams of Map.Entry which contains null key+values by adding .collect(toHashMap()), for example:
Map<String, Object> paramMap = params.stream().collect(toHashMap());
System.out.println(paramMap);
// prints {key1=1, key2=null}
The modern methods of the standard library, including the methods in the stream package, don’t like nulls as keys or values in maps. Generally for good reasons: nulls are problematic. You may consider a different design where keys with null values are omitted from your map. paramMap.get(yourKey) will still return the null that you say you want.
There could still be situations where you got legitimate reasons for wanting one or more null values in the map. To obtain that you may use the classic methods from the introduction of the Java collections framework in Java 1.2. It gets just a little wordier:
private static Map<String, Object> toParamMap(List<Map.Entry<String, Object>> params) {
Map<String, Object> paramMap = new HashMap<>();
params.forEach(param -> paramMap.put(param.getKey(), param.getValue()));
return paramMap;
}
Trying it out with your example:
List<Map.Entry<String, Object>> params = Arrays.asList(
new AbstractMap.SimpleEntry<>("key1", 1),
new AbstractMap.SimpleEntry<>("key2", null)
);
Map<String, Object> paramMap = toParamMap(params);
System.out.println(paramMap);
Output is a map with a null value in it:
{key1=1, key2=null}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With