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.
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...
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.
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"
}
Related
This question already has answers here:
How can non-final fields be used in a anonymous class class if their value can change?
(1 answer)
Lambdas: local variables need final, instance variables don't
(10 answers)
Why can an anonymous class access non-final class member of the enclosing class
(4 answers)
Closed 4 years ago.
This question is similar to Lambdas: local variables need final, instance variables don't,but the only difference is this question is valid even without lambda expressions i.e. valid even on Java7.
Here is the code snippet below.
public class MyClass {
Integer globalInteger = new Integer(1);
public void someMethod() {
Integer localInt = new Integer(2);
Runnable runnable = new Runnable() {
#Override
public void run() {
globalInteger = new Integer(11);//no error
localInt = new Integer(22);//error here
}
};
}
}
I am allowed to reassign globalInteger a new value but not to localInteger. Why is this difference?
To understand why non-local variables are allowed to change, we first need to understand why local variables aren't. And that's because local variables are stored on the stack (which instance (or static) variables aren't).
The problem with stack variables is that they're going to disappear once their containing method returns. However the instance of your anonymous class might live longer than that. So if accessing local variables were implemented naively, using the local variable from inside the inner class after the method returned would access a variable on a stack frame that no longer exists. That would either lead to a crash, an exception or undefined behavior depending on the exact implementation. Since that's clearly bad, access to local variables is implemented via copying instead. That is, all the local variables that are used by the class (including the special variable this) are copied into the anonymous object. So when a method of the inner class accesses a local variable x, it's not actually accessing that local variable. It's accessing a copy of it stored inside the object.
But what would happen if a local variable changed after the object was created or if a method of the object changed the variable? Well, the former would cause the local variable to change, but not the copy in the object, and the latter would change the copy, but not the original. So either way the two versions of the variable would no longer be the same, which would be very counter-intuitive to any programmer who doesn't know about the copying going on. So to avoid this problem, you're only allowed to access local variables if their value is never changed.
Instance variables don't need to be copied because they won't disappear until their containing object is garbage collected (and static variables never disappear) - since the anonymous object will contain a reference to the outer this, this won't happen until the anonymous object is garbage collected as well. So since they aren't copied, modifying them doesn't cause any issues and there's no reason to disallow it.
Because JVM has no machine instruction to assign a variable located at any stack frame which is different from the current stack frame.
because the lambda function is not part of the class.
Think about the following code (small changes of yours):
public Runnable func() {
Integer localInt = new Integer(2);
Runnable runnable = new Runnable() {
#Override
public void run() {
globalInteger = new Integer(11);//no error
localInt = new Integer(22);//error here
}
};
return runnable;
}
//Somewhere in the code:
Runnable r = func();
r.run(); // At this point localInt is not defined.
The complier tells you the error that variable in inner class must be final or effectively final. This is due to Java's 8 closure and how JVM captures the reference. The restriction is that the reference captured in the lambda body must be final (not re-assignable), and complier needs to ensure it doesn't reference copies of local variables.
so if you access instance variable, your lambda is really referencing this instance of the surrounding class, which is effective final (non-changing reference). In addition, if you use a wrapper class or array, the complier error also goes away.
In a lambda, local variables need to be final, but instance variables don't. Why so?
The fundamental difference between a field and a local variable is that the local variable is copied when JVM creates a lambda instance. On the other hand, fields can be changed freely, because the changes to them are propagated to the outside class instance as well (their scope is the whole outside class, as Boris pointed out below).
The easiest way of thinking about anonymous classes, closures and labmdas is from the variable scope perspective; imagine a copy constructor added for all local variables you pass to a closure.
In a document of project lambda, State of the Lambda v4, under Section 7. Variable capture, it is mentioned that:
It is our intent to prohibit capture of mutable local variables. The
reason is that idioms like this:
int sum = 0;
list.forEach(e -> { sum += e.size(); });
are fundamentally serial; it is quite difficult to write lambda bodies
like this that do not have race conditions. Unless we are willing to
enforce—preferably at compile time—that such a function cannot escape
its capturing thread, this feature may well cause more trouble than it
solves.
Another thing to note here is, local variables are passed in the constructor of an inner class when you access them inside your inner class, and this won't work with non-final variable because value of non-final variables can be changed after construction.
While in case of an instance variable, the compiler passes a reference of the object and object reference will be used to access instance variables. So, it is not required in case of instance variables.
PS : It is worth mentioning that anonymous classes can access only final local variables (in Java SE 7), while in Java SE 8 you can access effectively final variables also inside lambda as well as inner classes.
In Java 8 in Action book, this situation is explained as:
You may be asking yourself why local variables have these restrictions.
First, there’s a key
difference in how instance and local variables are implemented behind the scenes. Instance
variables are stored on the heap, whereas local variables live on the stack. If a lambda could
access the local variable directly and the lambda were used in a thread, then the thread using the
lambda could try to access the variable after the thread that allocated the variable had
deallocated it. Hence, Java implements access to a free local variable as access to a copy of it
rather than access to the original variable. This makes no difference if the local variable is
assigned to only once—hence the restriction.
Second, this restriction also discourages typical imperative programming patterns (which, as we
explain in later chapters, prevent easy parallelization) that mutate an outer variable.
Because instance variables are always accessed through a field access operation on a reference to some object, i.e. some_expression.instance_variable. Even when you don't explicitly access it through dot notation, like instance_variable, it is implicitly treated as this.instance_variable (or if you're in an inner class accessing an outer class's instance variable, OuterClass.this.instance_variable, which is under the hood this.<hidden reference to outer this>.instance_variable).
Thus an instance variable is never directly accessed, and the real "variable" you're directly accessing is this (which is "effectively final" since it is not assignable), or a variable at the beginning of some other expression.
Putting up some concepts for future visitors:
Basically it all boils down to the point that compiler should be able to deterministically tell that lambda expression body is not working on a stale copy of the variables.
In case of local variables, compiler has no way to be sure that lambda expression body is not working on a stale copy of the variable unless that variable is final or effectively final, so local variables should be either final or effectively final.
Now, in case of instance fields, when you access an instance field inside the lambda expression then compiler will append a this to that variable access (if you have not done it explicitly) and since this is effectively final so compiler is sure that lambda expression body will always have the latest copy of the variable (please note that multi-threading is out of scope right now for this discussion). So, in case instance fields, compiler can tell that lambda body has latest copy of instance variable so instance variables need not to be final or effectively final. Please refer below screen shot from an Oracle slide:
Also, please note that if you are accessing an instance field in lambda expression and that is getting executed in multi-threaded environment then you could potentially run in problem.
It seems like you are asking about variables that you can reference from a lambda body.
From the JLS §15.27.2
Any local variable, formal parameter, or exception parameter used but not declared in a lambda expression must either be declared final or be effectively final (§4.12.4), or a compile-time error occurs where the use is attempted.
So you don't need to declare variables as final you just need to make sure that they are "effectively final". This is the same rule as applies to anonymous classes.
Within Lambda expressions you can use effectively final variables from the surrounding scope.
Effectively means that it is not mandatory to declare variable final but make sure you do not change its state within the lambda expresssion.
You can also use this within closures and using "this" means the enclosing object but not the lambda itself as closures are anonymous functions and they do not have class associated with them.
So when you use any field (let say private Integer i;)from the enclosing class which is not declared final and not effectively final it will still work as the compiler makes the trick on your behalf and insert "this" (this.i).
private Integer i = 0;
public void process(){
Consumer<Integer> c = (i)-> System.out.println(++this.i);
c.accept(i);
}
Here is a code example, as I didn't expect this either, I expected to be unable to modify anything outside my lambda
public class LambdaNonFinalExample {
static boolean odd = false;
public static void main(String[] args) throws Exception {
//boolean odd = false; - If declared inside the method then I get the expected "Effectively Final" compile error
runLambda(() -> odd = true);
System.out.println("Odd=" + odd);
}
public static void runLambda(Callable c) throws Exception {
c.call();
}
}
Output:
Odd=true
YES, you can change the member variables of the instance but you CANNOT change the instance itself just like when you handle variables.
Something like this as mentioned:
class Car {
public String name;
}
public void testLocal() {
int theLocal = 6;
Car bmw = new Car();
bmw.name = "BMW";
Stream.iterate(0, i -> i + 2).limit(2)
.forEach(i -> {
// bmw = new Car(); // LINE - 1;
bmw.name = "BMW NEW"; // LINE - 2;
System.out.println("Testing local variables: " + (theLocal + i));
});
// have to comment this to ensure it's `effectively final`;
// theLocal = 2;
}
The basic principle to restrict the local variables is about data and computation validity
If the lambda, evaluated by the second thread, were given the ability to mutate local variables. Even the ability to read the value of mutable local variables from a different thread would introduce the necessity for synchronization or the use of volatile in order to avoid reading stale data.
But as we know the principal purpose of the lambdas
Amongst the different reasons for this, the most pressing one for the Java platform is that they make it easier to distribute processing of collections over multiple threads.
Quite unlike local variables, local instance can be mutated, because it's shared globally. We can understand this better via the heap and stack difference:
Whenever an object is created, it’s always stored in the Heap space and stack memory contains the reference to it. Stack memory only contains local primitive variables and reference variables to objects in heap space.
So to sum up, there are two points I think really matter:
It's really hard to make the instance effectively final, which might cause lots of senseless burden (just imagine the deep-nested class);
the instance itself is already globally shared and lambda is also shareable among threads, so they can work together properly since we know we're handling the mutation and want to pass this mutation around;
Balance point here is clear: if you know what you are doing, you can do it easily but if not then the default restriction will help to avoid insidious bugs.
P.S. If the synchronization required in instance mutation, you can use directly the stream reduction methods or if there is dependency issue in instance mutation, you still can use thenApply or thenCompose in Function while mapping or methods similar.
First, there is a key difference in how local and instance variables are implemented behind the scenes. Instance variables are stored in the heap, whereas local variables stored in the stack.
If the lambda could access the local variable directly and the lambda was used in a thread, then the thread using the lambda could try to access the variable after the thread that allocated the variable had deallocated it.
In short: to ensure another thread does not override the original value, it is better to provide access to the copy variable rather than the original one.
According to the doc Local variables in java are declared in methods, constructors, or blocks.
In the below Class A isn't x a local variable too since it is in blocks({}) i know they are called as instance variable but i am confused? If yes Access modifiers cannot be used for local variables but i am sure i can add public private protected ? It also says that local variable are stored in stack but as per the below code x will be stored in heap right since they are part of the instance?
class A{
private int x = 5; // Isn't this a local varibale too since it is in blocks
}
.
class A{
public void function(){
int x = 5; // this is a local variable since it is declared in a function
private int x2=5; // Error Access modifiers cannot be used for local variables
}
}
In the below Class A isn't x a local variable too since it is in blocks({})
No. It's not in a block. It's in a class declaration, but that's not a block as such. "Block" isn't synonymous with "text in braces".
To be a bit clearer, local variables are declared in:
Methods
Constructors
Static initializers
Instance initializers
If you look at the production for a class declaration, that's not a Block (unlike the production for static initializers and instance initializers).
In the below Class A isn't x a local variable too since it is in
blocks({})
Your x is not a local variable, it's an instance variable. Block means, instance initialization block or static block or try catch block.
Access modifiers cannot be used for local variables but i am sure i
can add public private protected ?
It doesn't make sense to have access modifiers to method local variables, since, method local variable can only be accessed inside the method.
I'm not entirely sure where you are reading. Local variables are values declared inside a method.
There is no special keyword designating a variable as local; that determination comes entirely from the location in which the variable is declared — which is between the opening and closing braces of a method.
Taken from here.
A local variable is a variable that has a local scope and is generally not expected to last a long time.
If you declare a variable inside a method, that variable will only be relevant while that method is being executed, and after the method finishes the variable will be discarded.
An instance variable is a variable that is bound to an instance of "something" and is generally considered to last as long as that "something" lasts.
If you declare a variable inside a class, then when you create a new instance of the class the variable will also be created and pinned onto the class. The variable will be there as long as the instance object of the class that you created exists, if you decide to discard the instance of the class you made, then the instance variable gets discarded as well.
Hope this was intuitive.
I was watching a tutorial on youtube and the topic was private variables. We usually set variables in java like this:
class hello {
public static void main(String args[]) {
String x;
x = "Hello"
}
}
but in that tutorial, the string type was declared out of the method like this:
class hello {
private String x;
public void apples() {
x = "this is a private variable.";
System.out.println(x);
}
}
As you can see it was not the main method, but i want to ask that do private variables always have to be out of method or what?
I am a beginner so this will be really helpful to know as i don't want to cram up knowledge to prevent confusion and also because it is a matter of fact that people who cram up code never become a good programmer.
do private variables always have to be out of method or what?
That's right. A variable inside a method is a local variable and can not have any access modifiers such as private, public or protected. These modifiers can only be applied to member variables, i.e. variables that are declared in the class scope.
If you think about it, it makes a lot of sense, since local variables can't be accessed by another class anyway. Not even another object of the same class or another method in the same object.
Related question:
What is the difference between a member variable and a local variable?
Cass variables must be declared to be one of the following types:
Public
Protected
Public
In the first example, the variable is local to the function: that is, it's specifically bound to method hello.main().
In that case, it's only accessible within that method function. It's not a class variable, so it doesn't need its access level to be set.
In the second example, the variable is a class variable. When you have a class variable, you can set it to private (can only be accessed by an object of that class), protected (accessed by inherited classes), or public (can be accessed outside of the object). The many methods possible inside the class can then access that class variable.
When you have a variable set inside a class definition, and not inside a method, it is called a "field" or "property" or "attribute." The way you define the accessibility of the field is required since multiple methods within the class can refer to it.
When you have a variable set within any method, it can only be accessed inside of that method, and can't be accessed outside (unless you use a reference pointer or pass it through method arguments).
A private variable in Java is a variable Globally accessible to the class and only to that class (and of course any other methods in the containing class).
A variable declared within a method can be accessed only within the scope of the method. A variable declared inside an if statement is only accessible inside the if statement .... and so on.
Its best to have as little private variable as possible because of performance issues. Lets say you have 100 private variables declared in a class. Your class contains 10 methods and each method utilizes 10 variables. When instantiating an object then your object is created instantiating olso the 100 private variables. If you make you variables local to your methods, then no variable is created on instantiation of the class, and 10 variables are used each time you access a method....
There are also other types of variables in java, to better comprehend you can start from here http://docs.oracle.com/javase/tutorial/java/nutsandbolts/variables.html
I think what's confusing you is the distinction between a local variable (declared in a method), and a member variable (declared in a class, outside of the class's methods).
A local variable exists just while the method that it's declared in is running. It comes into existence at the point that it's declared, then goes out of scope later, when the next } character occurs (other than those that match { characters that aren't opened yet). This effectively means that the variable disappears in a puff of smoke - it can't be used once it's gone out of scope.
But a member variable lives inside an object. That means it gets created when the object is created, and destroyed when the object is destroyed. So it typically lives for a much longer duration than the local variables do. Member variables can sometimes be used by objects other than the object that they belong to; and there are some quite complex rules around when it's possible to do this.
The private modifier on a member variable just means that it can only be accessed by code that's in the class that the object belongs to.
but i want to ask that do private variables always have to be out of method or what?.
Well, It doesn't make sense actually to make a variable private in a method. Because variables declared in a method are stack variables and they have narrower scope than a private one. As they can be accessed only in the method they are declared in and private variables have scope in the whole class they are declared in.
Any variable created with in a scope ( code block bounded inside { } ) is a local variable of that scope; and not accessible out side the block.
Also private variables is term which comes into picture when you talk about classes and define a member which is not accessible outside class.
I have the following code:
public class BookLib {
void f() {
final int x = 5; // Line 1
class MyCLass {
void print() {
System.out.println(x);
}
}
}
}
I don't understand why should use final variable in this case (Line 1)?
You've created an inner class here. Since the life-time of objects of this class can potentially be much greater than the runtime of the method invocation (i.e. the object can still exist long after the method has returned), it needs to "preserve" the state of local variables that it can access.
This preserving is done by creating an (invisible, synthetic) copy inside the inner class and automatically replacing all references to the local variable with references to that copy. This could lead to strange effects when the local variable were modified after the inner class object was created.
To avoid this, there is a requirement that all local variables that you access this way are final: this ensures that there is only ever one possible value for the local variable and no inconsistencies are observed.
This specific rule can be found in §8.1.3 Inner Classes and Enclosing Instances of the JLS:
Any local variable, formal method parameter or exception handler parameter used but not declared in an inner class must be declared final. Any local variable, used but not declared in an inner class must be definitely assigned (§16) before the body of the inner class.
Here you create an inner class. In order to access the context of execution, the references to the variables should stay intact, otherwise an error behaviour is observed. In order to guarantee this, you should declare your variable final: thus one can't change it.
See detailed explanation here.
From kathy sierra scjp Book
The local variables of the method live on the stack, and exist only for the lifetime of the method. We already know that the scope of a local variable is limited to the method the variable is declared in. When the method ends, the stack frame is blown away and the variable is history. But even after the method completes, the inner class object created within it might still be alive on the heap if, for example, a reference to it was passed into some other code and then stored in an instance variable. Because the local variables aren't guaranteed to be alive as long as the method-local inner class object, the inner class object can't use them. Unless the local variables are marked final!
So you have a local final variable and method-local inner class. A method-local inner class cannot use non-final variables declared within method (including parameters).
To go more deeply into this:
Method-local inner class can be instantiated only within method where the class is defined. The local variables live on stack for the lifetime of the method. As the method ends, the local variables disappear, however the inner class object created still lives.
It's a matter of lifetime/scope.