Java 8 Streams - collecting values ​​that may be null

I have the following code:

private static <T> Map<String, ?> getDifference(final T a, final T b, final Map<String, Function<T, Object>> fields) { return fields.entrySet().stream() .map(e -> { final String name = e.getKey(); final Function<T, Object> getter = e.getValue(); final Object pairKey = getter.apply(a); final Object pairValue = getter.apply(b); if (Objects.equals(pairKey, pairValue)) { return null; } else { return Pair.of(name, pairValue); } }) .filter(Objects::nonNull) .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); } 

Now the pair of Value may be zero. To avoid NPE, as described here , during the "collection" I want me to send only those values ​​that are not non-zero. If null, I want to send "".

So, I tried to replace the last line with the following:

 .collect(Collectors.toMap(Pair::getKey,Optional.ofNullable(Pair::getValue).orElse("")); 

And its other modifications:

 .collect(Collectors.toMap(pair -> pair.getKey(), Optional.ofNullable(pair -> pair.getValue()).orElse("")); 

Not compiled. I'm not sure what is needed here. Any help?

+5
source share
2 answers

You have the wrong syntax. toMap() second parameter must be lambda, so

 .collect(Collectors.toMap( pair -> pair.getKey(), pair -> Optional.ofNullable(pair.getValue()).orElse("") )); 

OR

you can change the map() section as follows

 return Pair.of(name, Optional.ofNullable(pairValue).orElse("")); 

and use your original collect()

+4
source

You can simply compile in a HashMap that allows null values ​​without the need for Optional :

 private static <T> Map<String, Object> getDifference( final T a, final T b, final Map<String, Function<T, Object>> fields) { return fields.entrySet().stream() .map(e -> { final Function<T, Object> getter = e.getValue(); final Object value = getter.apply(b); return Objects.equals(getter.apply(a),value)? null: Pair.of(e.getKey(), value); }) .filter(Objects::nonNull) .collect(HashMap::new, (m,p) -> m.put(p.getKey(),p.getValue()), Map::putAll); } 

By the way, it is not recommended to use wildcards in reverse types, they can make the life of callers without undue severity without any benefit.

For comparison, the same operation without Stream is here:

 private static <T> Map<String, Object> getDifference( final T a, final T b, final Map<String, Function<T, Object>> fields) { HashMap<String, Object> result = new HashMap<>(); fields.forEach((key, getter) -> { final Object value = getter.apply(b); if(!Objects.equals(getter.apply(a), value)) result.put(key, value); }); return result; } 

Of course, this will also work with the extra:

 private static <T> Map<String, Optional<Object>> getDifference( final T a, final T b, final Map<String, Function<T, Object>> fields) { HashMap<String, Optional<Object>> result = new HashMap<>(); fields.forEach((key, getter) -> { final Object value = getter.apply(b); if(!Objects.equals(getter.apply(a), value)) result.put(key, Optional.ofNullable(value)); }); return result; } 

But if all you want to do is replace null an empty string, you don't need Optional :

 private static <T> Map<String, Object> getDifference( final T a, final T b, final Map<String, Function<T, Object>> fields) { HashMap<String, Object> result = new HashMap<>(); fields.forEach((key,getter) -> { final Object value = getter.apply(b); if(!Objects.equals(getter.apply(a), value)) result.put(key, value==null? "": value); }); return result; } 

and well, this substitution will also work from ready-made source code if you just do it in the map function instead of the collector:

 private static <T> Map<String, ?> getDifference(final T a, final T b, final Map<String, Function<T, Object>> fields) { return fields.entrySet().stream() .map(e -> { final String name = e.getKey(); final Function<T, Object> getter = e.getValue(); final Object pairKey = getter.apply(a); final Object pairValue = getter.apply(b); if (Objects.equals(pairKey, pairValue)) { return null; } else { return Pair.of(name, pairValue==null? "": pairValue); } }) .filter(Objects::nonNull) .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); } 

or

 private static <T> Map<String, Object> getDifference( final T a, final T b, final Map<String, Function<T, Object>> fields) { return fields.entrySet().stream() .map(e -> { final Function<T, Object> getter = e.getValue(); final Object pairValue = getter.apply(b); return Objects.equals(getter.apply(a), pairValue)? null: Pair.of(e.getKey(), pairValue==null? "": pairValue); }) .filter(Objects::nonNull) .collect(Collectors.toMap(Pair::getKey, Pair::getValue)); } 
+4
source

Source: https://habr.com/ru/post/1275368/


All Articles