在封闭范围内定义的局部变量必须是最终的或有效的最终

时间:2017-04-03 20:55:15

标签: java

我试图打印出x/mol的百分比,但我似乎无法让它发挥作用。我收到此错误:Local variable x defined in an enclosing scope must be final or effectively final

它说这发生在22行,并没有简单的解决方法。什么是java的作用域,以及如何将x添加到作用域中,以便我的计时器可以读取它。

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!");

    }
}

4 个答案:

答案 0 :(得分:4)

您不能在嵌套类中使用局部变量,因为JVM要求它final或至少“有效最终”(这意味着x的值无法在路)。

你可以通过在main之外声明x作为静态变量来绕过它:

static volatile BigInteger x = new BigInteger("0");
public static void main(String[] args) {
....

请注意它也被声明为volatile,因为主线程修改了它,并且您希望Timer查看更新的x值(如果您没有声明它挥发Timer可能会看到陈旧的价值观)。

答案 1 :(得分:1)

创建一个类来保存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;
    }
}

然后在第14行左右的代码中。

final MyContainer myContainer = new MyContainer(new BigDecimal(0));

然后在你的计时器中,

System.out.println(myContainer.getX().divide(mol) + "%");

答案 2 :(得分:1)

为了在嵌套类中使用方法的局部变量,该变量必须是final或&#34;有效的最终&#34;,其中后者意味着编译器可以证明变量的值在整个方法执行期间不会改变。如果不满足该条件,那么嵌套类对变量的使用的语义将不清楚 - 将使用该变量的多个值中的哪一个?

有几种方法可以解决这个问题:

  1. 出于特定目的,您似乎应该将x声明为类变量而不是局部变量。 (它不能是实例变量,因为您是从静态上下文访问它。​​)但是,您可以选择

  2. 使x最终或有效最终。例如,将对x的引用复制到final变量,并使ActionListener访问该副本而不是访问x

  3. 或者您可以使用可以传递ActionListener的构造函数创建和实例化一个已命名的x实现类,嵌套或顶级。然后,该实现可以使用它初始化的引用来访问x引用的对象,但由于BigInteger是不可变的,因此无法修改该对象。

答案 3 :(得分:0)

使用委托模式

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;

import javax.swing.Timer;

public class BigDecimalTest {
    public static void main(String[] args) {
        StringBuffer writable = new StringBuffer;
        final MyBigInteger x = new MyBigInteger("0");
        BigInteger mol = new BigInteger("602214179000000000000000");
        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.append("a");
             x.add(new BigInteger("1"));
        } while (x.compareTo(mol) < 0);

        File file = new File("molA.txt");
        try (
                FileWriter fw = new FileWriter(file);
                BufferedWriter bw = new BufferedWriter(fw);
                ) {
            bw.write(writable.toString());
            System.out.println("Done");
        } catch (IOException e) {
            System.out.println(e);
        }
        t.stop();
        System.out.println("Finished!");
    }
}


import java.math.BigInteger;
import java.util.Random;

public class MyBigInteger extends BigInteger {
    private static final long serialVersionUID = 1L;

    private BigInteger delegate = null;

    public MyBigInteger(byte[] arg0) {
        super(arg0);
        delegate = new BigInteger(arg0);
    }

    public MyBigInteger(String arg0) {
        super(arg0);
        delegate = new BigInteger(arg0);
    }

    public MyBigInteger(int arg0, byte[] arg1) {
        super(arg0, arg1);
        delegate = new BigInteger(arg0, arg1);
    }

    public MyBigInteger(String arg0, int arg1) {
        super(arg0, arg1);
        delegate = new BigInteger(arg0, arg1);
    }

    public MyBigInteger(int arg0, Random arg1) {
        super(arg0, arg1);
        delegate = new BigInteger(arg0, arg1);
    }

    public MyBigInteger(int bitLength, int certainty, Random rnd) {
        super(bitLength, certainty, rnd);
        delegate = new BigInteger(bitLength, certainty, rnd);
    }

    @Override
    public MyBigInteger divide(BigInteger divisor) {
        delegate = delegate.divide(divisor);
        return this;
    }

    @Override
    public MyBigInteger add(BigInteger addition) {
        delegate = delegate.add(addition);
        return this;
    }

    @Override
    public String toString() {
        return delegate.toString();
    }

    @Override
    public int compareTo(BigInteger compare) {
        return delegate.compareTo(compare);
    }
}

我担心您尝试将510Zb(510 Zetta Bytes)写入文件,或者甚至尝试创建一个长的String。我猜你的系统会崩溃,因为你没有足够的内存来容纳字符串,你没有足够的磁盘空间来存放交换文件,或者写下了molA.txt文件。如果它确实有效,它可能需要很长时间才能运行。