Why do Lambda functions require final variables

Recently, It got me thinking why do lambda functions require final variables after all. This is not a requirement in Kotlin.

For example, this code runs fine in kotlin

fun main(args: Array<String>) {
    var index = 5
    val list = mutableListOf<Int>()
    list.forEach(Consumer { o: Int ->
        index = 10
        println(o * index)

Whereas a similar function in Java will give error

public static void main(String[] args) {

    Integer index = 5;
    List<Integer> list = new ArrayList<>();
    list.forEach(o-> {

This will fail with a compilation failure

Error:(15, 13) java: local variables referenced from a lambda expression must be final or effectively final

Effectively final is a new concept in Java 8.

… starting in Java SE 8, a local class can access local variables and parameters of the enclosing block that are final or effectively final. A variable or parameter whose value is never changed after it is initialized is effectively final.

But the question remains, why does a variable accessed inside a lambda function needs to be effectively final?

The answer has been given here

It’s basically due to the way Java manages closures.

When you create an instance of an anonymous inner class, any variables which are used within that class > have their values copied in via the autogenerated constructor. This avoids the compiler having to autogenerate various extra types to hold the logical state of the “local variables”, as for example the C# compiler does… (When C# captures a variable in an anonymous function, it really captures the variable - the closure can update the variable in a way which is seen by the main body of the method, and vice versa.)

As the value has been copied into the instance of the anonymous inner class, it would look odd if the > variable could be modified by the rest of the method - you could have code which appeared to be working with an out-of-date variable (because that’s effectively what would be happening… you’d be working with a copy taken at a different time). Likewise if you could make changes within the anonymous inner class, developers might expect those changes to be visible within the body of the enclosing method.

Making the variable final removes all these possibilities - as the value can’t be changed at all, you > don’t need to worry about whether such changes will be visible. The only ways to allow the method and the anonymous inner class see each other’s changes is to use a mutable type of some description. This could be the enclosing class itself, an array, a mutable wrapper type… anything like that. Basically it’s a bit like communicating between one method and another: changes made to the parameters of one method aren’t seen by its caller, but changes made to the objects referred to by the parameters are seen.

If you’re interested in a more detailed comparison between Java and C# closures, I have an article which > goes into it further. I wanted to focus on the Java side in this answer :)