Java - changing the value of a final variable from within a lambda

前端 未结 3 776
不知归路
不知归路 2021-01-01 03:28

In Java I have the following code

List myList = new ArrayList<>();
for (int i=0;i<9;i++) {
    myList.add(i);
}

Integer sum = 0;

m         


        
相关标签:
3条回答
  • 2021-01-01 03:34

    Not exactly the answer you are looking for, but in most scenarios you won't need to modify that inside the lambda. This is because it's not idiomatic for lambdas to be state-changing in a proper functional style.

    What you can do to achieve your result is use any of the higher-level functions provided to mask the "accumulator", and then assign:

    sum = myList.stream().mapToInt(x->x).sum();
    
    0 讨论(0)
  • 2021-01-01 03:39

    A lambda is basically an anonymous class. You can only access final local variables from anonymous class.

    What you need is a wrapper class that can modify its content. For a quick hack, you can use AtomicInteger in this case:

    AtomicLong sum = new AtomicLong(0);
    myList.forEach(i -> {
      sum.addAndGet(i); // does not matter getAndAdd or addAndGet
    });
    
    sum.get(); // to get the value
    

    Another way is, if you are using Intellij IDEA, the IDE can suggest you to transform the variable into final one element array (as in darijan's answer).

    0 讨论(0)
  • 2021-01-01 03:41

    Try with:

    final Integer[] sum = new Integer[1];
    sum[0] = 0;
    
    myList.forEach(i -> {
        sum[0] = sum[0] + i; // does not compile, sum needs to be final or effectively final
    }); 
    

    Since lambda is actually a syntactic sugar for initializing an anonymous class (and overriding a method).

    It's the same as if you have written:

    final Integer[] sum = new Integer[1];
    sum[0] = 0;
    
    myList.forEach(new Consumer() {
        public void accept(Integer element) {
            sum[0] = sum[0] + element;
        }
    });
    

    The variable that comes from outer scope and that you use within inner scope must be final (in this example sum). That is simply because Java does not support closures. Therefore, outer variable must be marked as final. Since Integer itself is immutable (if you declare it final, you cannot change it anymore), you have to use a wrapper object or an array (as I did).

    You can find more useful info here:

    • Why are only final variables accessible in anonymous class?
    • Cannot refer to a non-final variable inside an inner class defined in a different method
    0 讨论(0)
提交回复
热议问题