19

The Java documentation for Local Classes says that:

In addition, a local class has access to local variables. However, a local class can only access local variables that are declared final. When a local class accesses a local variable or parameter of the enclosing block, it captures that variable or parameter. For example, the PhoneNumber constructor can access the local variable numberLength because it is declared final; numberLength is a captured variable.

What is captured variable,what is its use and why is that needed? Please help me in understanding the concept of it.

Chaitanya
  • 15,403
  • 35
  • 96
  • 137

3 Answers3

25

What is captured variable,what is its use and why is that needed?

A captured variable is one that has been copied so it can be used in a nested class. The reason it has to be copied is the object may out live the current context. It has to be final (or effectively final in Java 8) so there is no confusion about whether changes to the variable will be seen (because they won't)

Note: Groovy does have this rule and a change to the local variable can mean a change to the value in the enclosing class which is especially confusing if multiple threads are involved.

An example of capture variable.

public void writeToDataBase(final Object toWrite) {
    executor.submit(new Runnable() {
        public void run() {
             writeToDBNow(toWrite);
        }
    });
    // if toWrite were mutable and you changed it now, what would happen !?
}
// after the method returns toWrite no longer exists for the this thread...
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 1
    Could you please clarify (or give an example) of the object (which object?) outliving the current context? – user949300 Feb 25 '14 at 20:26
  • Thanks a lot Peter, can you please give me an example in Java program that explains how the object can outlive the context and that caused the designers of Java to have a restriction on variables to be final or effective final. – Chaitanya Feb 25 '14 at 20:29
  • @user2065083 Added an example for out living, and gave reason for doing this. Not sure how to make it clearer. – Peter Lawrey Feb 25 '14 at 20:41
  • 1
    Thanks Peter for providing an example, but I have least knowledge in multithreading/concurrency, so I am finding it difficulty in understanding. I was expecting some other basic examples, or some example using Java's Comparator interface is used more commonly. – Chaitanya Feb 25 '14 at 20:47
  • @user2065083 Comparators are usually stateless. Giving them captured variables is rare. – Peter Lawrey Feb 25 '14 at 20:49
  • @user2065083 Understanding how capture variables and compilers work in such case is relatively obscure. Multi-threading is relatively common and simple by comparison so perhaps it is not surprising you have trouble grasping it. ;) For example, how many Java developers have even heard of `this$0`, maybe a hundred or so in the world. How many developers have heard of multi-threading and executors, more than half I expect. – Peter Lawrey Feb 25 '14 at 20:51
  • Thanks for the example - it helped some. If, at the "what would happen?" line, the code did `toWrite = null`, the compiler isn't smart enough to say "use the value from **before**"? In effect, pass `toWrite` _by value_ to the Runnable? (especially as it gets copied?) Geez, doesn't seem like rocket science there, but I'm not writing the compiler... :-) – user949300 Feb 25 '14 at 21:12
  • how does the "copying" work? is it like a shallow copy? – Yamcha Nov 14 '17 at 19:57
  • @Yamcha the value is copied for primitives and references. The object referenced is not copied, shallow or deep. – Peter Lawrey Nov 15 '17 at 08:32
  • Is it okay to think those "captured variables" are the same as 'closure'? – starriet Jan 20 '21 at 08:02
9

Here is a post describing it: http://www.devcodenote.com/2015/04/variable-capture-in-java.html

Here is a snippet from the post:

”It is imposed as a mandate by Java that if an inner class defined within a method references a local variable of that method, that local variable should be defined as final.”

This is because the function may complete execution and get removed from the process stack, with all the variables destroyed but it may be the case that objects of the inner class are still on the heap referencing a particular local variable of that function. To counter this, Java makes a copy of the local variable and gives that as a reference to the inner class. To maintain consistency between the 2 copies, the local variable is mandated to be “final” and non-modifiable.

Abhishek Jain
  • 4,478
  • 8
  • 34
  • 51
4

A captured variable is one from the outside of your local class - one declared in the surrounding block. In some languages this is called a closure.

In the example from the Oracle Docs (simplified) the variable numberLength, declared outside of class PhoneNumber, is "captured".

final int numberLength = 10;  // in JDK7 and earlier must be final...

class PhoneNumber {
   // you can refer to numberLength here...  it has been "captured"
}
user949300
  • 15,364
  • 7
  • 35
  • 66