I re-opened this question after it was closed as a duplicate of Variable used in lambda expression should be final or effectively final. IMO, the answers to that question are confusing.
There's two parts to this question;
What did you do wrong? You tried to assign a value to b
, but b
is a local variable from a scope that encloses the new Runnable() ...
You aren't allowed to do that.
Why is it not allowed? Simply,* It's because b
will cease to exist when main()
returns, but the run()
method might not be called until after main()
returns.
Why did the compiler not complain about x
and z
?
It's because they are effectively final
. I.e., they are initialized but they never are assigned. Because they never are assigned, their initial values can be safely copied into the new Runnable() ...
object.
Your program would compile if you changed it to not assign b
:
...
int x = 10;
int z=0;
Thread t3 = new Thread(new Runnable() {
public void run() {
System.out.println(x * z);
}
});
...
In this case the x
and the z
in the run()
method actually are different variables from the x
and the z
in main()
. They are automatically initialized to the same values as the main routine's x
and z
when the new Runnable
object is created, but they continue to exist, as members of the new object, even after main()
has returned.
Why can't b
also be copied?
If you really want to get into that, then it's time to go back to that other answer.
* The complete answer is more subtle, and IMO, answers on the "duplicate" lose their way in discussing the subtleties. Mostly they are true, but exposure to the complete truth does not always help a newbie who is just beginning to learn difficult new concepts like anonymous inner classes, lambdas, and threads.