java: local variable looper is accessed from within inner class; needs to be declared final, but then variable might not have been initialized

I'm using something a bit like the command pattern to create a class which implements a simple interface for a method I reuse frequently, but in different ways.

I was able to get it working using a couple different methods, but I prefer this one, courtesy of Jon Skeet.

public class InterfaceProblemExample implements Runnable{

    public static void main(String... args) {
        new InterfaceProblemExample().run();
    }

    @Override
    public void run() {
        int dim = 3;
        final double[][] oldMatrix = new double[dim][dim];
        final double[][] newMatrix = new double[dim][dim];

        final AtomicReference<Looper> wrapper = new AtomicReference<Looper>();
        Looper looper = new Looper(dim, new Commandable() {
            @Override
            public void execute() {
                int axis1 = wrapper.get().getiAxis1();
                int axis2 = wrapper.get().getiAxis2();
                newMatrix[axis1][axis2] = oldMatrix[axis1][axis2] + 2.5;
            }
        });
        wrapper.set(looper);
        looper.execute();
    }

    public interface Commandable {
        public abstract void execute();
    }

    public class Looper implements Commandable {

        private Commandable command;
        private int iAxis1;
        private int iAxis2;
        private int dim;

        public Looper(int dim, Commandable command) {
            this.command = command;
            this.dim = dim;
        }

        public void setCommand(Commandable command) {
            this.command = command;
        }

        @Override
        public void execute() {
            for (iAxis2 = 1; iAxis2 < dim; iAxis2++) {
                for (iAxis1 = 0; iAxis1 < iAxis2; iAxis1++) {
                    command.execute();
                }
            }
        }

        public int getiAxis1() {
            return iAxis1;
        }

        public int getiAxis2() {
            return iAxis2;
        }

        public int getDim() {
            return dim;
        }
    }
}
Jon Skeet
people
quotationmark

You've effectively got a cyclic dependency: your Looper needs to be initialized with the Commandable, and the Commandable needs to be initialized with the Looper. The compiler is absolutely right to complain - imagine if the Looper constructor called command.execute() - that would try to use the looper variable (within the anonymous inner class) before you initialize it.

You need to break that cycle. For example:

  • You could make the Looper have a setCommandable method
  • You could make your Commandable implementation have a setLooper method
  • You could pass the Looper into the execute method

As a really hacky way round this, you could use an array or an atomic reference as a "wrapper":

public void run() {
    final AtomicReference<Looper> wrapper = new AtomicReference<Looper>();
    Looper looper = new Looper(new Commandable() {
        @Override
        public void execute() {
            System.out.println("This is easy: ");
            System.out.println("This isn't easy: " + wrapper.get().getI());
        }
    });
    wrapper.set(looper);
    looper.execute();
}

But that's pretty nasty.

people

See more on this question at Stackoverflow