Oma*_*que 48 java java-8 java-stream
我有一个Map<String, Double>
,并希望将地图中的所有值乘以2,比方说,但是将空值保持为空.
我显然可以使用for循环来做到这一点,但是想知道是否有更清洁的方法呢?
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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
有时候返回的地图someMapFunction
是一个不可变的地图,所以这不能用就地做Map.replaceAll
.我无法想出一个更清洁的流解决方案.
Era*_*ran 62
我的第一反应是提出一个Stream
输入Map
的entrySet
该值映射到新的价值,并与终止collectors.toMap()
.
不幸的是,值mapper函数返回时Collectors.toMap
抛出.因此,它不适用于您输入的值.NullPointerException
null
null
Map
作为替代方案,因为您无法改变您的输入Map
,我建议您创建它的副本然后调用replaceAll
:
Map<String, Double> adjustedMap = new HashMap<>(someMap);
adjustedMap.replaceAll ((k,v) -> v != null ? 2*v : null);
Run Code Online (Sandbox Code Playgroud)
Pet*_*ček 25
作为流式传输和/或复制解决方案的替代方案,Google Guava中Maps.transformValues()
存在实用方法:
Map<String, Double> adjustedMap = Maps.transformValues(someMap, value -> (value != null) ? (2 * value) : null);
Run Code Online (Sandbox Code Playgroud)
这将返回原始地图的惰性视图,该视图不会自行执行任何工作,但会在需要时应用给定的函数.这既可以是一个亲(如果你不可能永远都需要所有的值,这会为你节省一些计算时间)和CON(如果你需要相同的值多次,或者如果你需要进一步修改someMap
,而不adjustedMap
看到变化)取决于您的使用情况.
已有很多答案.其中一些似乎对我有点怀疑.在任何情况下,他们中的大多数都null
以一种形式或另一种形式内联检查.
抽象阶梯向上迈出一步的方法如下:
您想要将一元运算符应用于地图的值.因此,您可以实现一个将一元运算符应用于映射值的方法.(到现在为止还挺好).现在,您需要一个"特殊"的一元运算符null
-safe.然后,您可以null
围绕原始运算符包装-safe一元运算符.
这里显示了三个不同的运算符(其中一个是运算符Math::sin
):
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;
}
}
Run Code Online (Sandbox Code Playgroud)
我认为这很干净,因为它很好地区分了应用运算符和执行null
-check的问题.它是安全的null
,因为...方法名称是这样说的.
(有人可能会说拉调用包裹运营商进入nullSafe
一个进的apply
方法,但在这里,这不是问题的关键)
编辑:
根据预期的应用程序模式,可以执行类似的操作并通过调用将转换应用到适当位置,而无需创建新映射Map#replaceAll
您可以通过转换为流来实现这一目标,例如:
someMap.entrySet()
.forEach(entry -> {
if (entry.getValue() != null) {
adjustedMap.put(entry.getKey(), someMap.get(entry.getKey()) * 2);
} else {
adjustedMap.put(entry.getKey(), null);
}
});
Run Code Online (Sandbox Code Playgroud)
可以缩短为:
someMap.forEach((key, value) -> {
if (value != null) {
adjustedMap.put(key, value * 2);
} else {
adjustedMap.put(key, null);
}
});
Run Code Online (Sandbox Code Playgroud)
所以,如果你有一张地图:
Map<String, Double> someMap = new HashMap<>();
someMap.put("test1", 1d);
someMap.put("test2", 2d);
someMap.put("test3", 3d);
someMap.put("testNull", null);
someMap.put("test4", 4d);
Run Code Online (Sandbox Code Playgroud)
你会得到这个输出:
Run Code Online (Sandbox Code Playgroud){test4=8.0, test2=4.0, test3=6.0, testNull=null, test1=2.0}
归档时间: |
|
查看次数: |
4608 次 |
最近记录: |