Java 8 Lambda问题在递增计数时有效最终

我想在以下场景中使用Java 8 Lambda表达式,但我得到的是在封闭范围内定义的局部变量fooCount必须是final或者有效的final 。 我理解错误信息的内容,但我需要在这里计算百分比,所以需要增加fooCountbarCount然后计算百分比。 那么实现它的方法是什么:

  // key is a String with values like "FOO;SomethinElse" and value is Long final Map map = null; .... private int calculateFooPercentage() { long fooCount = 0L; long barCount = 0L; map.forEach((k, v) -> { if (k.contains("FOO")) { fooCount++; } else { barCount++; } }); final int fooPercentage = 0; //Rest of the logic to calculate percentage .... return fooPercentage; } 

我有一个选择是在这里使用AtomicLong而不是long但我想避免它,所以稍后如果可能我想在这里使用并行流。

流中有一个count方法可以为您计数。

 long fooCount = map.keySet().stream().filter(k -> k.contains("FOO")).count(); long barCount = map.size() - fooCount; 

如果要进行并行化, .stream()更改为.parallelStream()

或者,如果您尝试手动增加变量,并使用流并行化,那么您可能希望使用类似AtomicLong东西来保证线程安全。 即使编译器允许,一个简单的变量也不是线程安全的。

要获得数字,匹配和非匹配元素,您可以使用

 Map result = map.keySet().stream() .collect(Collectors.partitioningBy(k -> k.contains("FOO"), Collectors.counting())); long fooCount = result.get(true); long barCount = result.get(false); 

但由于您的源是一个Map ,它知道它的总大小,并且想要计算一个百分比,不需要barCount ,这个特定的任务可以解决为

 private int calculateFooPercentage() { return (int)(map.keySet().stream().filter(k -> k.contains("FOO")).count() *100/map.size()); } 

两种变体都是线程安全的,即将stream()更改为parallelStream()parallelStream()执行操作,但是,此操作不太可能受益于并行处理。 你需要庞大的钥匙串或地图来获得好处……

我同意其他答案,表明你应该使用countpartitioningBy

只是用一个例子来解释primefaces性问题,请考虑以下代码:

 private static AtomicInteger i1 = new AtomicInteger(0); private static int i2 = 0; public static void main(String[] args) { IntStream.range(0, 100000).parallel().forEach(n -> i1.incrementAndGet()); System.out.println(i1); IntStream.range(0, 100000).parallel().forEach(n -> i2++); System.out.println(i2); } 

这将返回i1的预期结果100000,但i2的不确定数字小于(在我的测试运行中在50000和80000之间)。 原因应该是非常明显的。