Issue with Java 8 Lambda for effective final while incrementing counts

后端 未结 3 1276
走了就别回头了
走了就别回头了 2021-01-26 17:04

I want to use Java 8 Lambda expression in following scenario but I am getting Local variable fooCount defined in an enclosing scope must be final or effectively final.

相关标签:
3条回答
  • 2021-01-26 17:56

    To get both numbers, matching and non-matching elements, you can use

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

    But since your source is a Map, which knows its total size, and want to calculate a percentage, for which barCount is not needed, this specific task can be solved as

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

    Both variants are thread safe, i.e. changing stream() to parallelStream() will perform the operation in parallel, however, it’s unlikely that this operation will benefit from parallel processing. You would need humongous key strings or maps to get a benefit…

    0 讨论(0)
  • 2021-01-26 17:57

    There is a count method in stream to do counts for you.

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

    If you want parallelisation, change .stream() to .parallelStream().

    Alternatively, if you were trying to increment a variable manually, and use stream parallelisation, then you would want to use something like AtomicLong for thread safety. A simple variable, even if the compiler allowed it, would not be thread-safe.

    0 讨论(0)
  • 2021-01-26 18:10

    I agree with the other answers indicating you should use countor partitioningBy.

    Just to explain the atomicity problem with an example, consider the following code:

    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);
    }
    

    This returns the expected result of 100000 for i1 but an indeterminate number less than that (between 50000 and 80000 in my test runs) for i2. The reason should be pretty obvious.

    0 讨论(0)
提交回复
热议问题