需要帮助将传统java转换为流



在下面的代码中,我试图删除输入映射键中没有根的所有节点和叶。输入是映射<rootId:String,listOf(根,节点,叶子(>

工作逻辑

@NotNull
private static Map<String, List<Element>> removeOrphanNodes(Map<String, List<Element>> mapOfAllProcesses) {
Map<String,List<Element>> refinedRootMap= new HashMap<>();
for(Map.Entry<String,List<Element>>entrySet: mapOfAllProcesses.entrySet())
{
if(entrySet.getValue().size()>1)
refinedRootMap.put(entrySet.getKey(),entrySet.getValue());
else {
Element loneElement = entrySet.getValue().get(0);
if (entrySet.getKey().equals(loneElement.getIdAsString()))
refinedRootMap.put(entrySet.getKey(),entrySet.getValue());
else if(loneElement.getCurrentOperations()!=null && loneElement.getCurrentOperations().iterator().next().getId().toHexString().equals(entrySet.getKey()))
refinedRootMap.put(entrySet.getKey(),entrySet.getValue());
}
}
return refinedRootMap;
}

上面的代码按预期工作。我想使用流来实现相同的功能,但getCurrentOperations抛出空指针

我的尝试

return mapOfAllProcesses.entrySet().stream().filter(entry -> entry.getValue().size()>1 || entry.getValue().stream()
.anyMatch(
element-> element.getIdAsString().equals(entry.getKey())||element.getCurrentOperations().stream().findFirst().get().getId().toHexString().equals(entry.getKey())
)).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

不要这样做

Stream API不是循环或传统迭代构造的替代品。

放入流的理想代码是:

  • 执行一个函数(读取数据,加载数据(
  • 可以并行化
  • 没有副作用(例如,不接触任何其他东西(

您的代码满足最后一个项目符号,我不确定中间的项目符号,它肯定会根据条件做更多的工作,这。。。不是流媒体的理想。

也许解决这个问题的更好方法是重新思考您正在使用的数据结构?您使用的是Map<K, List<V>>,它可以在Guava Multimap中上下文化。也许这就是需要进行第一次改进的地方——为此使用更合适的数据结构?

element.getCurrentOperations()返回的集合为null时,为了避免引发NPE,可以尝试使用Stream.ofNullable()。在这个集合为空(因此可选集合将为空(的情况下,从可选集合中提取结果时的伪默认值会有所帮助。

return mapOfAllProcesses.entrySet().stream()
.filter(entry -> entrySet.getValue().size() > 1 ||
entry.getValue().stream()
.anyMatch(
element -> element.getIdAsString().equals(entry.getKey())
||
Stream.ofNullable(element.getCurrentOperations()).findFirst()
.map(operation -> operation.getId().toHexString())
.orElse("").equals(entry.getKey())
))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue
));

值得注意的是,这两个片段(命令式和函数式(都非常复杂,因此考虑将一些功能片段提取到单独的方法中是明智的。

应该这样做,但我认为这样做没有任何好处。它稍微短了一点,但并没有真正简单,也绝对没有任何清晰

@NotNull
private static Map<String, List<Element>> removeOrphanNodes(Map<String, List<Element>> mapOfAllProcesses) {
return mapOfAllProcesses.entrySet().stream().filter((entry) -> 
(entry.getValue().size() > 1)
|| entry.getKey().equals(entry.getValue().get(0).getIdAsString())
|| Optional.ofNullable(entry.getValue().get(0).getCurrentOperations())
.stream()
.map((ops) -> ops.iterator().next().getId().toHexString())
.anyMatch((s) -> s.equals(entry.getKey()))
).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

此版本通过将返回值捕获为Optional来处理getCurrentOperations()可以返回null的事实。当getCurrentOperations()返回null,而anyMatch()在空流上返回false时,Optional的流将为空。

内部流的map()可以省略,以便为其anyMatch()提供更复杂的谓词,但我认为带有map()的版本更清晰。

最新更新