Edited: I need to change the values of several variables as they run several times thorugh a timer. I need to keep updating the values with every iteration through the timer. I cannot set the values to final as that will prevent me from updating the values however I am getting the error I describe in the initial question below:
I had previously written what is below:
I am getting the error "cannot refer to a non-final variable inside an inner class defined in a different method".
This is happening for the double called price and the Price called priceObject. Do you know why I get this problem. I do not understand why I need to have a final declaration. Also if you can see what it is I am trying to do, what do I have to do to get around this problem.
public static void main(String args[]) {
int period = 2000;
int delay = 2000;
double lastPrice = 0;
Price priceObject = new Price();
double price = 0;
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
price = priceObject.getNextPrice(lastPrice);
System.out.println();
lastPrice = price;
}
}, delay, period);
}
Java doesn't support true closures, even though using an anonymous class like you are using here (
new TimerTask() { ... }
) looks like a kind of closure.edit - See the comments below - the following is not a correct explanation, as KeeperOfTheSoul points out.
This is why it doesn't work:
The variables
lastPrice
and price are local variables in the main() method. The object that you create with the anonymous class might last until after themain()
method returns.When the
main()
method returns, local variables (such aslastPrice
andprice
) will be cleaned up from the stack, so they won't exist anymore aftermain()
returns.But the anonymous class object references these variables. Things would go horribly wrong if the anonymous class object tries to access the variables after they have been cleaned up.
By making
lastPrice
andprice
final
, they are not really variables anymore, but constants. The compiler can then just replace the use oflastPrice
andprice
in the anonymous class with the values of the constants (at compile time, of course), and you won't have the problem with accessing non-existent variables anymore.Other programming languages that do support closures do it by treating those variables specially - by making sure they don't get destroyed when the method ends, so that the closure can still access the variables.
@Ankur: You could do this:
Good explanations for why you can't do what you're trying to do already provided. As a solution, maybe consider:
Seems like probably you could do a better design than that, but the idea is that you could group the updated variables inside a class reference that doesn't change.
To solve the problem above, different languages make different decisions.
for Java, the solution is as what we see in this article.
for C#, the solution is allow side-effects and capture by reference is the only option.
for C++11, the solution is to allow the programmer make the decision. They can choose to capture by value or by reference. If capturing by value, no side-effects would occur because the variable referenced is actually different. If capture by reference, side-effects may occur but the programmer should realize it.
The main concern is whether a variable inside the anonymous class instance can be resolved at run-time. It is not a must to make a variable final as long as it is guaranteed that the variable is inside the run-time scope. For example, please see the two variables _statusMessage and _statusTextView inside updateStatus() method.
I just wrote something to handle something along the authors intention. I found the best thing to do was to let the constructor take all the objects and then in your implemented method use that constructor objects.
However, if you are writing a generic interface class, then you have to pass an Object, or better a list of Objects. This could be done by Object[] or even better, Object ... because it is easier to call.
See my example piece just below.
Please see this post about Java closures that supports this out of the box: http://mseifed.blogspot.se/2012/09/closure-implementation-for-java-5-6-and.html
Version 1 supports passing of non-final closures with autocasting:
https://github.com/MSeifeddo/Closure-implementation-for-Java-5-6-and-7/blob/master/org/mo/closure/v1/Closure.java
If you want to change a value in a method call within an anonymous class, that "value" is actually a
Future
. So, if you use Guava, you can write