Search code examples
springlambdajava-8immutabilityconstructor-injection

How to access instance variables of a constructor injected class be used inside lambda


The Customer class uses constructor injection (recommended over field injection), but the instance field is not usable inside a lambda.

@Component
public class Customer {

  private final Account account;

  @Autowired
  public Customer(final Account account) {
    this.account = account;
  }

  // Works perfectly fine
  Callable propCallable = new Callable<String>(){
    @Override
    public String call() throws Exception {
        return account.accountId();
    }
  };

  //Shows warning : Variable account might not have been initialized
  Callable lambdaCallable = () -> {
    return account.accountId();
  };
}

I'm just curious to know if there is a better way to use instance variable inside the lambda, rather than anonymous class?

Note: I prefer to keep account as final.

Thanks in advance


Solution

  • There are some differences between an anonymous class and lambda. In this case the main one is:

    Compilation – Anonymous compiles to a class, while lambda is an invokedynamic instruction

    Now about the compiler error. By Java order of initialization rules, your lambda initialization happens before the 'account' assignment in the constructor. Not sure, but there is no such error with the anonymous class because of the compilation difference.

    So, you can return the lambda from method, or move 'lambdaCallable' initialization to the constructor.

    public class DemoApplication {
    
        public class Customer {
    
            private final Account account;
    
            public Customer(final Account account) {
                this.account = account;
            }
    
            // Works perfectly fine
            Callable propCallable = new Callable<String>(){
                @Override
                public String call() throws Exception {
                    return account.accountId();
                }
            };
    
            Callable getCallable() {
                return account::getId;
            }
    
    //        Callable lambdaCallable = () -> {
    //            return account.accountId();
    //        };
        }
    }