我有一个validate
方法,该方法返回一个boolean
。
我正在按以下方式调用此方法(Java 7):
boolean isValid = true;
for (String key: aMap.keySet()) {
isValid &= validate(key, aMap.get(key));
}
我想用Java 8重写此代码。
Java 8允许使用以下方法遍历Map:
aMap.forEach((k,v) -> validate(k, v));
但这不起作用:
aMap.forEach((k,v) -> isValid &= validate(k, v));
问题
如何将Java 7代码重写为Java 8以实现相同的结果?
注意:
我问了类似的问题here。这篇文章的不同之处在于,这次我想遍历Map
的所有项目(使用validate
方法来构建验证报告)。如果没有发生验证错误,isValid
必须返回true
;如果至少发生一个错误,则false
必须返回。
答案 0 :(得分:4)
您可以使用
boolean isValid = aMap.entrySet().stream()
.map(e -> validate(e.getKey(), e.getValue()))
.reduce(true, Boolean::logicalAnd);
因为与anyMatch
,allMatch
等不同,Reduction不会发生短路。但是,您需要执行所有validate
方法调用,这表明该方法内有副作用。重要的是要了解这些副作用必须是无干扰的,即这些方法的调用顺序无关紧要,甚至多个元素的并发求值也不应破坏它。
即使满足这些要求,也不鼓励在功能操作中产生此类副作用。例如,下一位查看您的代码的开发人员可能会说:“嘿,看来我们应该在这里使用allMatch
”…
所以我会坚持下去。但是,在处理Map
的关联时,您不应在entrySet()
上循环以对每个键执行查找,而应使用
boolean isValid = true;
for(Map.Entry<String, ValueType> e: aMap.entrySet())
isValid &= validate(e.getKey(), e.getValue());
从Java 10开始,您可以使用
boolean isValid = true;
for(var e: aMap.entrySet()) isValid &= validate(e.getKey(), e.getValue());
消除该循环中最令人讨厌的语法元素。
答案 1 :(得分:1)
aMap.forEach((k,v) -> isValid &= validate(k, v));
的问题在于,在lambda表达式中捕获的变量应为final
或effectively final
。这与Java中的anonymous inner classes
相同。
因此,要回答您的查询,可以将isValid
转换为final
一个元素数组,如下所示:
final boolean[] isValid = {true};
,然后
aMap.forEach((k,v) -> isValid[0] &= validate(k, v));
您也可以将其设置为atomic
,但这将需要更多代码更改。这种解决方案要简单得多。