I'm trying to print out the percentage of x/mol
, but I cannot seem to get it to work. I am getting a this error: Local variable x defined in an enclosing scope must be final or effectively final
It says this happens at line 22, and there is no easy fix for it. What is java's scope, and how can I add x to the scope so that my timer can read it.
import java.math.BigInteger;
import javax.swing.Timer;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.io.IOException;
public class mol {
public static void main(String[] args) {
String writable = "";
BigInteger x = new BigInteger("0");
BigInteger mol = new BigInteger("602214179000000000000000");
File file = new File("molA.txt");
BufferedWriter bw = null;
FileWriter fw = null;
Timer t;
t = new Timer(10000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.out.println(x.divide(mol) + "%");
System.out.println(x);
}
});
System.out.println("Starting...");
t.start();
do {
writable += "a";
x = x.add(new BigInteger("1"));
} while (x.compareTo(mol) < 0);
try {
fw = new FileWriter(file);
bw = new BufferedWriter(fw);
bw.write(writable);
System.out.println("Done");
} catch (IOException e) {
System.out.println(e);
} finally {
try {
if (bw != null)
bw.close();
if (fw != null)
fw.close();
} catch (IOException ex) {
System.out.println(ex);
}
}
t.stop();
System.out.println("Finished!");
}
}
You can't use a local variable inside a nested class since the JVM requires it to be final
or at least "effectively final" (which means the value of x
cannot be modified down the road).
You can by-pass it by declaring x
outside of main as a static variable:
static volatile BigInteger x = new BigInteger("0");
public static void main(String[] args) {
....
Pay attention that it is also declared to be volatile
since the main thread modified it and you want the Timer to see the updated value of x
(if you don't declare it volatile the Timer might see stale values).
In order to use a method's local variable inside a nested class, the variable must either be either final
or "effectively final", where the latter means that the compiler can prove that that the variable's value will not change during the entire execution of the method. If that condition were not satisfied then the semantics of the nested class's usage of the variable would be unclear -- which of the multiple values of the variable would be used, at which point?
There are several ways you could address the problem:
For your particular purpose, it looks like you should declare x
as a class variable instead of a local variable. (It cannot be an instance variable because you are accessing it from static context.) You do, however, have the alternative to
make x
final or effectively final. For example, copy the reference to x
to a final
variable, and make your ActionListener
access that copy instead of accessing x
.
Or you could create and instantiate a named ActionListener
implementation class, nested or top-level, with a constructor to which you could pass x
. That implementation can then use the reference it is initialized with to access the object to which x
refers, but since BigInteger
s are immutable, it could not modify that object.
Create a class to hold the BigDecimals
public class MyContainer {
private BigDecimal x = null;
public MyContainer(BigDecimal x) {
this.x = x;
}
public BigDecimal getX() {
return x;
}
public void setX(BigDecimal x) {
this.x = x;
}
}
Then in your code on line 14 or so.
final MyContainer myContainer = new MyContainer(new BigDecimal(0));
Then in your timer,
System.out.println(myContainer.getX().divide(mol) + "%");
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With