我理解为什么lambda表达式不能改变局部变量,我理解他们可以访问和mututae类字段。对我来说,lambdas在许多情况下创建了更具表现力的代码,我想更频繁地使用它们。
我的问题是使用lambda的最佳实践不是单方法对象替换,而是简化代码如下:
int pairsFound = 0;
for (Map.Entry<String, Integer> entry : counters.entrySet())
{
if (entry.getValue() == 2)
pairsFound++;
}
到
pairsFound = map.forEach((key, value) ->
{
int z = 0;
if (value == 2)
z++;
return z;
});
或
map.forEach((key, value) ->
{
if (value == 2)
pairsFound++;
});
一种解决方案是使parisFound
成为实例字段。但是,对于从未在单一方法之外使用过的变量进行实例化,对我来说似乎是一种代码味道。此外,如果封闭类是静态的(例如在测试运行中),这将不起作用。
是否还有其他方法可以从一个lambda中获取信息,而这种方式的安全性并不比使用每个循环更安全?我理解lambda可能存在并发问题,但在我的大多数简化用例中,我不知道lambda是否会比它替换的更安全。
答案 0 :(得分:10)
此方案最简单的方法是创建一个流,根据entry.getValue() == 2
条件进行过滤,然后count()
结果。像这样:
long pairsFound = map.values().stream().filter(v -> v == 2).count(); //using values() rather than entrySet() makes the code more readable
一般的教训是,使用lambdas需要一种不同的思维模式,一种更接近函数式编程(lambda起源的概念),而不是试图在其上强加相同的命令式原则。从lambda中获取信息的正确方法是评估它们,而不是通过副作用。
答案 1 :(得分:4)
为了与您当前的实施保持一致,您需要使用map
而不是forEach
来返回值,然后reduce
来累积:
pairsFound = map.values().stream()
.map(value -> value == 2 ? 1 : 0)
.reduce(Integer::sum);