Java 如何使映射在其每个可选值是否存在时成为可选的
我有一个带有许多可选值的映射:Java 如何使映射在其每个可选值是否存在时成为可选的,java,java-stream,Java,Java Stream,我有一个带有许多可选值的映射: Map 我想将此地图转换为可选的: 可选 如果每个可选都存在:则可选应该存在 如果任何可选不存在:可选应不存在 我尝试过这样做,我怀疑我的代码会起作用,但这有点冗长: 最终地图mycolmap; 最终可选optionalMap=MyColMap .entrySet() .stream() .地图(e->e .getValue() .flatMap(值->可选.of( 新建AbstractMap.SimpleEntry( e、 getKey(), 价值 )
Map
我想将此地图转换为可选的:
可选
- 如果每个
可选
都存在:则可选
应该存在
- 如果任何
可选
不存在:可选
应不存在
我尝试过这样做,我怀疑我的代码会起作用,但这有点冗长:
最终地图mycolmap;
最终可选optionalMap=MyColMap
.entrySet()
.stream()
.地图(e->e
.getValue()
.flatMap(值->可选.of(
新建AbstractMap.SimpleEntry(
e、 getKey(),
价值
)
))
)
.收集(
()->可选.of(新HashMap()),
(optAcc,optEntry)->optAcc.flatMap(
acc->optEntry.map(
条目->{
acc.put(entry.getKey(),entry.getValue());
返回acc;
})
),
(optAcc1,optAcc2)->optAcc1.flatMap(
acc1->optAcc2.map(
acc2->{
acc1.putAll(acc2);
返回acc1;
}
)
)
);
有更好的方法吗?“更好”意味着正确性、性能和美观。我希望答案能够在一个流中完成整个操作。以下方法可以完成此任务:
Map<MyCoolKey, Optional<MyCoolValue>> input;
Optional<Map<MyCoolKey, MyCoolValue>> output = convertMapWithOptionals(input);
Map输入;
可选输出=convertMapWithOptionals(输入);
我提出了这种方法的两种“风格”:
1) 不情愿:首先检查所有,然后开始转换
<K, V> Optional<Map<K, V>> convertMapWithOptionals(Map<K, Optional<V>> map) {
if (!map.values().stream().allMatch(Optional::isPresent)) {
return Optional.empty();
}
return Optional.of(map.entrySet().stream().collect(Collectors.toMap(
Map.Entry::getKey, entry -> entry.getValue().get()
)));
}
可选convertMapWithOptionals(地图地图){
如果(!map.values().stream().allMatch(可选::isPresent)){
返回可选的.empty();
}
返回可选的.of(map.entrySet().stream().collect(Collectors.toMap(
Map.Entry::getKey,Entry->Entry.getValue().get()
)));
}
2) 急切:必要时开始转换并中止
<K, V> Optional<Map<K, V>> convertMapWithOptionals(Map<K, Optional<V>> map) {
Map<K, V> result = new HashMap<>();
for (Map.Entry<K, Optional<V>> entry : map.entrySet()) {
if (!entry.getValue().isPresent()) {
return Optional.empty();
}
result.put(entry.getKey(), entry.getValue().get());
}
return Optional.of(result);
}
可选convertMapWithOptionals(地图地图){
映射结果=新的HashMap();
对于(Map.Entry:Map.entrySet()){
如果(!entry.getValue().isPresent()){
返回可选的.empty();
}
put(entry.getKey(),entry.getValue().get());
}
返回可选。of(结果);
}
这里是纯流溶液的一个例子(没有if
s和三元运算符)
final Map mycolmap=new HashMap();
可选输出=可选的.of(myColMap)
.filter(map->map.values().stream().allMatch(可选::isPresent))
.map(地图->地图)
.entrySet()
.stream()
.收集(
Map.Entry::getKey,
entry->entry.getValue().get()
))
);
这并不过分复杂-过滤和映射是流的用途 我认为你试图把所有的逻辑都放在一条流中,这太复杂了。只需过滤掉空的可选s,然后查看元素的数量是否相同:
Optional<Map<MyCoolKey, MyCoolValue>> result = Optional.of(
map.entrySet()
.stream()
.filter(e -> e.getValue().isPresent())
.collect(
Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get())
)
)
.filter(x-> x.size() == map.size());
Optional result=Optional.of(
map.entrySet()
.stream()
.filter(e->e.getValue().isPresent())
.收集(
Collectors.toMap(Map.Entry::getKey,e->e.getValue().get())
)
)
.filter(x->x.size()==map.size());
如果我对问题理解正确,您可以使用reduce
而不是collect
。它允许您在采集期间更改累加器
Optional<Map<MyCoolKey, MyCoolValue>> optionalMap = myCoolMap
.entrySet()
.stream()
.reduce(Optional.<Map<MyCoolKey, MyCoolValue>>of(new HashMap<>()),
(acc, entry) -> {
if (!acc.isPresent()) {
return acc;
}
if (!entry.getValue().isPresent()) {
return Optional.empty();
}
acc.get().put(entry.getKey(), entry.getValue().get());
return acc;
},
(acc, acc1) -> {
if (acc.isPresent() && acc1.isPresent()) {
acc.get().putAll(acc1.get());
return acc;
}
return Optional.empty();
}
);
可选optionalMap=MyColMap
.entrySet()
.stream()
.reduce(可选的.of(新的HashMap()),
(acc,条目)->{
如果(!acc.isPresent()){
返回acc;
}
如果(!entry.getValue().isPresent()){
返回可选的.empty();
}
acc.get().put(entry.getKey(),entry.getValue().get());
返回acc;
},
(acc,acc1)->{
如果(根据isPresent()和&acc1.isPresent()){
acc.get().putAll(acc1.get());
返回acc;
}
返回可选的.empty();
}
);
因此,如果此映射长度为10000个项目,您还是要映射它,然后检查是否要返回它?@Danon您的解决方案将在所有元素上迭代两次。一个简单的不必要的映射并不比这更昂贵。这会给条目增加更多,但过早的优化是万恶之源,所以谁在乎呢。此外,10000项也没什么,Michael,你可以将其内联到一条语句中:result=Optional.of().filter(tmp->tmp.size()==map.size())
@MalteHartwig是的,我更喜欢它。谢谢@迈克尔:我同意@Danon。请注意,如果映射有很多元素,即使第一个值是Optional.empty()
,您也将收集整个映射,而不是使用短路操作(因此它不会测试所有剩余元素)。我发现此解决方案非常不直观且不可读,即使它返回的Optional.empty()中有一些值
Optional<Map<MyCoolKey, MyCoolValue>> optionalMap = myCoolMap
.entrySet()
.stream()
.reduce(Optional.<Map<MyCoolKey, MyCoolValue>>of(new HashMap<>()),
(acc, entry) -> {
if (!acc.isPresent()) {
return acc;
}
if (!entry.getValue().isPresent()) {
return Optional.empty();
}
acc.get().put(entry.getKey(), entry.getValue().get());
return acc;
},
(acc, acc1) -> {
if (acc.isPresent() && acc1.isPresent()) {
acc.get().putAll(acc1.get());
return acc;
}
return Optional.empty();
}
);