There already are many answers. Some of them seem a bit dubious to me. In any case, most of them inline the null
-check in one form or the other.
An approach that takes one step up the abstraction ladder is the following:
You want to apply an unary operator to the values of the map. So you can implement a method that applies an unary operator to the values of the map. (So far, so good). Now, you want a "special" unary operator that is null
-safe. Then, you can wrap a null
-safe unary operator around the original one.
This is shown here, with three different operators (one of them being Math::sin
, for that matter) :
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.UnaryOperator;
public class MapValueOps
{
public static void main(String[] args)
{
Map<String, Double> map = new LinkedHashMap<String, Double>();
map.put("A", 1.2);
map.put("B", 2.3);
map.put("C", null);
map.put("D", 4.5);
Map<String, Double> resultA = apply(map, nullSafe(d -> d * 2));
System.out.println(resultA);
Map<String, Double> resultB = apply(map, nullSafe(d -> d + 2));
System.out.println(resultB);
Map<String, Double> resultC = apply(map, nullSafe(Math::sin));
System.out.println(resultC);
}
private static <T> UnaryOperator<T> nullSafe(UnaryOperator<T> op)
{
return t -> (t == null ? t : op.apply(t));
}
private static <K> Map<K, Double> apply(
Map<K, Double> map, UnaryOperator<Double> op)
{
Map<K, Double> result = new LinkedHashMap<K, Double>();
for (Entry<K, Double> entry : map.entrySet())
{
result.put(entry.getKey(), op.apply(entry.getValue()));
}
return result;
}
}
I think this is clean, because it nicely separates the concerns of applying the operator and performing the null
-check. And it is null
-safe, because ... the method name says so.
(One could argue to pull the call to wrap the operator into a nullSafe
one into the apply
method, but that's not the point here)
Edit:
Depending on the intended application pattern, one could do something similar and apply the transformation in place, without creating a new map, by calling Map#replaceAll