如何从Java 8中的lambda表达式中获取信息?

时间:2016-01-12 16:49:45

标签: java lambda

我理解为什么lambda表达式不能改变局部变量,我理解他们可以访问和mututae类字段。对我来说,lambdas在许多情况下创建了更具表现力的代码,我想更频繁地使用它们。

我的问题是使用l​​ambda的最佳实践不是单方法对象替换,而是简化代码如下:

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是否会比它替换的更安全。

2 个答案:

答案 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);