Monday, October 21, 2019

Java Lambda Expression And Variable Scope

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"

Java lambda expression and variable 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"

lambda expression and variable scope

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

  1. Lambda Expressions in Java 8
  2. Functional Interfaces in Java
  3. How to Fix The Target Type of This Expression Must be a Functional Interface Error
  4. Java Lambda Expression And Exception Handling
  5. Java Lambda Expressions Interview Questions

You may also like-

  1. Method Reference in Java
  2. How Linked List class works internally in Java
  3. How ArrayList works internally in Java
  4. Why wait(), notify() and notifyAll() must be called inside a synchronized method or block?
  5. Synchronization in Java multithreading
  6. Best practices for exception handling in Java
  7. abstract class in Java
  8. How to create PDF from XML using Apache FOP

3 comments:

  1. Raj Gopal BhallamudiMarch 22, 2017 at 7:59 PM

    Pls also include hashcode in this() and super() with lambda expression example


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

    ReplyDelete
  2. Please assist as i am facing issue : Local variable flag defined in an enclosing scope must be final or effectively final

    logic: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!

    ReplyDelete
    Replies
    1. One of the way in that case is to use an array then you can change the value, in your case Boolean[] arr = {true};
      Your 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");
      }
      });

      Delete