As I understand it, Java does not have true closures. You can pass a function by chaperoning them with a class; however, not only is it verbose but also (because of Java’s memory model) any references in the anonymous class to variables defined in the environment where it was constructed are passed as copies. The language encourages us to remember this by only allowing anonymous classes to refer to final variables.
Which brings me to this code snippet I found in Bloch’s Effective Java:
import java.util.concurrent.*;
public class StopThread {
private static boolean stopRequested;
public static void main(String[] args)
throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!stopRequested)
i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
First, I expected the compiler to complain because stopRequested is nonfinal and I refer to it inside the anonymous class. My compiler didn’t complain.
Second, I expected the program to loop forever since, well, Java doesn’t support closures and if the anonymous class really is referring to the actual stopRequested variable from the environment it was constructed (and not a simple copy) then it seems like we have a closure here. Joshua Bloch also said the program loops forever on his computer. But mine runs for about a second and exits.
What part of the memory model am I misunderstanding?
The key thing you’re missing is that the anonymous class is a nested class. As such, it has an implicit reference to the instance of the containing class, and therefore members of the class.
It is only local variables which are required to be
finalfor use by anonymous classes.