If you remember, You can only access a local final variable inside an anonymous class, if you try to access a non-final local variable then compiler will complain, but things has changed a little bit in Java 8 with introduction of lambda expression. Since Java designer are expecting more and more usage of lambda expression they have relaxed that restriction a little bit by introducing a new concept called effectively final, which means now you can access a non-final variable inside anonymous class or lambda expression, provided its not changed after creation i.e. even if its not declared with final modifier but it still like a final variable. So, concept wise, the variable must still be treated as final variable but the final keyword is not mandatory anymore. This difference between final and effectively final will be more clear with an example of both anonymous class and lambda expression. Let's see that.
Accessing local variable inside Anonymous class in Java
Here is a Java program which shows how to access a local variable inside a Lambda expression and Anonymous class in Java, it wasn't possible before Java 8 but with this new concept called "effectively final" you can access a non-final variable inside Anonymous class now.
Before Java 8
package beginner;
/**
* Java Program to demonstrate how to access local variable
* inside Anonymous class and lambda expression in Java.
*
* @author WINDOWS 10
*
*/
public class HelloWorldApp {
public static void main(String... args){
// count must be final if you want to access it inside
// anonymous class
final int count = 10;
Thread t = new Thread(){
public void run(){
// Cannot refer to a non-final variable count
// inside an inner class defined in a different method
System.out.println(count);
}
};
t.start();
}
}
In Java 8 :
/**
* Java Program to demonstrate how to access local variable inside Anonymous
* class and lambda expression in Java.
*
* @author WINDOWS 10
*
*/
public class Java8Demo {
public static void main(String... args) {
// in Java 8, final is not mandatory
// unless you are not assigning value
// to the local variable again
int count = 10;
Thread t = new Thread() {
@Override
public void run() {
System.out.println(count); // Ok in Java 8
// local variables referenced from an inner class
// must be final or effectively final
// System.out.println(count++); // not ok
}
};
t.start();
}
}
You can see that its now possible to access a non-final local variable inside run() method which is inside an Anonymous class in above code. This is possible because variable count has not bee modified since declared, hence its effectively final in Java.
Accessing local variable inside lambda expression
In this example, we need to use the Runnable interface because java.lang.Thread class is not a functional interface in Java but Runnable is because of SAM rule. It has single abstract method run() which makes it a Functional interface.
public class Java8Demo {
public static void main(String... args) {
// you can access final or effectively fina variable
// inside lambda expression.
int count = 10;
Runnable r = () -> {
System.out.println(count); // Ok in Java 8
};
Thread t = new Thread(r);
t.start();
}
}
You can see that now you can access a non final variable inside anonymous class and lambda expression as long as its treated as final or its effectively final.
Absence of final keyword means compiler will not prevent you from assigning that variable a new value but it will still prevent if you access such variable inside anonymous class or lambda expression.
In short, you can only access either a final or effectively final variable inside lambdas and only difference between them is final keyword. It's mandatory to include final keyword for final variable but not for effectively final variable. Also for all other purpose, an effectively final variable is treated as non-final e.g. compiler will not prevent you from assigning a new value to it.
No comments:
Post a Comment