The body of a lambda expression in Java does not define a new scope; the lambda expression scope is the same as the enclosing scope.
Let's see it with an example, if there is already a declared variable i and lambda expression body declares a local variable i too, that will result in compiler error "Lambda expression's local variable i cannot re-declare another local variable defined in an enclosing scope"
Effectively Final in Java
When a lambda expression uses an assigned local variable from its enclosing space there is an important restriction;
Lambda expression in Java may only use local variable whose value doesn't change. That restriction is referred as
"variable capture" which is described as; lambda expression capture values, not variables. The local variables
that a lambda expression may use are known as effectively final
.
An effectively final variable is one whose value does not change after it is first assigned. There is no need to explicitly declare such a variable as final, although doing so would not be an error.
Let's see it with an example, we have a local variable i which is initialized with the value 7, with in the lambda expression we are trying to change that value by assigning a new value to i. This will result in compiler error- "Local variable i defined in an enclosing scope must be final or effectively final"
this() and super() with lambda expression in Java
this and super references with in a lambda expression are the same as in the enclosing context. Since a lambda expression does not define a new scope, the this keyword with in a lambda expression signifies the this parameter of the method where the lambda expression is residing.
@FunctionalInterface interface IFuncInt { int func(int num1, int num2); public String toString(); } public class LambdaVarDemo { public static void main(String[] args){ LambdaVarDemo lambdaDemo = new LambdaVarDemo(); lambdaDemo.getResult(); } public void getResult(){ IFuncInt funcInt = (num1, num2) -> { System.out.println("calling toString " + this.toString()); return num1 + num2; }; System.out.println("Result is " + funcInt.func(6, 7)); } @Override public String toString() { System.out.println("in class LambdaVarDemo toString()" ); return super.toString(); } }
Output
in class LambdaVarDemo toString() calling toString org.netjs.examples1.LambdaVarDemo@12c9b19 Result is 13
Here it can be seen that the expression this.toString() calls the toString method of the LambdaVarDemo object, not the toString() method of the IFuncInt instance. Please note that a functional interface may have the Object class public methods too in addition to the abstract method.
That's all for this topic Java Lambda Expression And Variable Scope. If you have any doubt or any suggestions to make please drop a comment. Thanks!
Related Topics
You may also like-
Pls also include hashcode in this() and super() with lambda expression example
ReplyDelete@FunctionalInterface
interface IFuncInt {
int func(int num1, int num2);
public String toString();
}
public class LambdaVarDemo {
public static void main(String[] args) {
LambdaVarDemo lambdaDemo = new LambdaVarDemo();
System.out.println("lambdaDemo hashcode="+lambdaDemo.hashCode());
lambdaDemo.getResult();
}
public void getResult() {
IFuncInt funcInt = (num1, num2) -> {
System.out.println("this hashcode="+ this.hashCode());
System.out.println("calling toString "+ this.toString());
return num1 + num2;
};
System.out.println("Result is "+ funcInt.func(1, 4));
}
@Override
public String toString() {
System.out.println("in class LambdaVarDemo toString()");
System.out.println("super hashcode="+ super.hashCode());
return Integer.toString(super.hashCode());
}
}
Please assist as i am facing issue : Local variable flag defined in an enclosing scope must be final or effectively final
ReplyDeletelogic:i want to execute if block, whenever flag is true , but using lamda expression i cannot reassign the flag variable.
List applications = applicationDao.getAll();
List appUser = appUserDao.getAll();
boolean flag = true;
applications.forEach( a -> {
for (MobileAppUser mobileAppUser : appUser) {
if(mobileAppUser.getId() == a.getAppUser().getId()) {
flag = false; //error: Local variable flag defined in an enclosing scope must be final or effectively final
continue;
}
}
if(flag) {
//want to execute some logic here
}
});
Thanks in advance!
One of the way in that case is to use an array then you can change the value, in your case Boolean[] arr = {true};
DeleteYour program with some changes -
List applications = Arrays.asList("A", "B");
List appUser = Arrays.asList("A", "B");
Boolean[] arr = {true};
//Boolean flag = false;
applications.forEach( a -> {
for (String mobileAppUser : appUser) {
if(mobileAppUser.equals("A")) {
arr[0] = false; //error: Local variable flag defined in an enclosing scope must be final or effectively final
break;
}else{
arr[0] = true;
}
}
if(!arr[0]) {
System.out.println("Here with false");
}else{
System.out.println("Here with true");
}
});