The Local variable name defined in an enclosing scope must be final or effectively final exception occurs where the local variable used in the lamda expression is not a final or effectively final variable. In the lamda expression, the local variable can only be used if the variable is final or effectively final. If the local variable is modified within the lamda expression encloser or beyond the lamda expression encloser, the Java exception Local variable name defined in an enclosing scope must be final or effectively final will be thrown.
The final variable in java is a variable that cannot be changed after initialization. The final variable value is assigned when the variable is initialised. If the value is changed after initialization, the exception Local variable name defined in an enclosing scope must be final or effectively final will be thrown.
The effectively final variable is a variable that should not be updated after initialization. The effectively final variable is not the final variable in java. The java variable that is not declared as the final variable but acts as the final variable is called the effectively final variable.
Lambda expression will only use a local variable whose value does not change. If the local variable value is changed, the java exception Local variable name defined in an enclosing scope must be final or effectively final will be thrown.
Exception
The java error message will be seen as below in the eclipse.
Local variable name defined in an enclosing scope must be final or effectively final
The stack trace of the exception Local variable name defined in an enclosing scope must be final or effectively final will be shown as shown below.
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Local variable name defined in an enclosing scope must be final or effectively final
at com.yawintutor.SubListTest.main(SubListTest.java:17)
Root Cause
Lambda expression will only use a local variable whose value does not change. If the local variable value is changed, the java exception will be thrown.The local variable is not expected to be the final variable. But this should be used as a final variable. The value of the variable can only be assigned at initialization. If the value is changed after initialization, the exception will be thrown.
Solution 1
The value of the local variable should be assigned as the variable is initialised at the time of declaration. If the value is assigned after the variable has been created, the exception Local variable name defined in an enclosing scope must be final or effectively final will be thrown.
In the example below, the string variable is declared and initialized with null. In the next line, the variable”name” is assigned with a value “Hello”. As the variable is not assigned with value while creating, the variable is not considered as a final variable. Hence the exception will be thrown. In the solution, the variable declaration and the assignment will be done in a single line. The variable is created with value assigned.
package com.yawintutor;
interface IPrinter {
void print();
}
public class SubListTest {
public static void main(String[] args) {
String name = null;
name="Hello";
IPrinter printer = ()->{
System.out.println(name);
};
printer.print();
}
}
Exception
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Local variable name defined in an enclosing scope must be final or effectively final
at com.yawintutor.SubListTest.main(SubListTest.java:14)
Solution
package com.yawintutor;
interface IPrinter {
void print();
}
public class SubListTest {
public static void main(String[] args) {
String name = "Hello";
IPrinter printer = ()->{
System.out.println(name);
};
printer.print();
}
}
Output
Hello
Solution 2
In certain cases, the local variable should be used in the lamda expression after the value has been changed. The exception “Local variable name defined in an enclosing scope must be final or effectively final” would be thrown in this situation. The work around is that a new final variable is created and assigned with a local variable after the change.
package com.yawintutor;
interface IPrinter {
void print();
}
public class SubListTest {
public static void main(String[] args) {
String name = "Hello";
name = "World";
IPrinter printer = ()->{
System.out.println(name);
};
printer.print();
}
}
Exception
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Local variable name defined in an enclosing scope must be final or effectively final
at com.yawintutor.SubListTest.main(SubListTest.java:14)
Solution
package com.yawintutor;
interface IPrinter {
void print();
}
public class SubListTest {
public static void main(String[] args) {
String name = "Hello";
name = "World";
final String tempName = name;
IPrinter printer = ()->{
System.out.println(tempName);
};
printer.print();
}
}
Output
World
Solution 3
In certain cases, the local variable with in the lamda expression need to be modified. If the value had been changed, the exception Local variable name defined in an enclosing scope must be final or effectively final would have been thrown. The work around is to create a new list and assign the local variable in it. The value can be modified either within or outside the lamda expression in the list.
package com.yawintutor;
interface IPrinter {
void print();
}
public class SubListTest {
public static void main(String[] args) {
String name = "Hello";
IPrinter printer = ()->{
name = "World";
System.out.println(name);
};
printer.print();
}
}
Exception
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Local variable name defined in an enclosing scope must be final or effectively final
at com.yawintutor.SubListTest.main(SubListTest.java:13)
Solution
A new array list is created and a name is added to the list. The array list is neither initialized nor reassigned. The value in the array list is changed. Hence the exception “Local variable name defined in an enclosing scope must be final or effectively final” will be resolved.
import java.util.List;
interface IPrinter {
void print();
}
public class SubListTest {
public static void main(String[] args) {
String name = "Hello";
List<String> nameList = new ArrayList<String>();
nameList.add(name);
IPrinter printer = ()->{
nameList.set(0,"World");
System.out.println(nameList.get(0));
};
printer.print();
}
}
Output
World