Warrick
Warrick

Reputation: 1963

Access interface variables defined in method

I'll just paste the code then explain what I need. I'm lost as to how to acheive this, and I can't even think of alternatives that fit my code very well.

public Transform findById(final int id) {
    final Transform returnTransform = null;

    execute(new IExecutor() {
        Transform returnTransform = null;
        @Override
        public boolean execute(Transform transform) {
            if (transform.getID() == id) {
                returnTransform = transform;
                return true;
            }
            return false;
        }
    });

    return <returnTransform>;
}

What I need, is get the variable 'returnTransform' from inside the interface and use it to return from the 'findById' method.
I can't define a variable in the method, because it has to be final to access within the method: and I need to change it.

One solution would be to define the 'returnTransform' variable directly in the class, but it seems tacky. Any other genius ideas from anyone?
Thanks :)

Upvotes: 1

Views: 393

Answers (3)

Konstantin Yovkov
Konstantin Yovkov

Reputation: 62864

You can create a local class, that wraps the Transform variable and exposes accessor methods for it. Then you can use a final wrapper instance and you will be allowed to change its internal state.

For example:

public Transform findById(final int id) {
    class Wrapper {
        private Transform returnTransform = null;

        Transform getReturnTransorm() { return returnTransform; }

        void setReturnTransform(Transform returnTransform) {
            this.returnTransform = returnTransform;
        }
    }
    final Wrapper wrapper = new Wrapper();
    execute(new IExecutor() {
        @Override
        public boolean execute(Transform transform) {
            if (transform.getID() == id) {
                wrapper.setReturnTransform(transform);
                return true;
            }
            return false;
        }
    });

    return wrapper.getReturnTransform();
}

Upvotes: 1

Dmitry Ginzburg
Dmitry Ginzburg

Reputation: 7461

You may define your own interface, which would have method to return returnTransform, something like:

public interface ExecutorWithTransform extends IExecutor {
    public Transform getTransform();
}

Then you should use this interface in code, when creating instance:

ExecutorWithTransform executor = new ExecutorWithTransform() {

    Transform returnTransform = null;

    public Transform getTransform() {
        return returnTransform;
    }

    @Override
    public boolean execute(Transform transform) {
        if (transform.getID() == id) {
            returnTransform = transform;
            return true;
        }
        return false;
    }
};

execute(executor);

return executor.getTransform();

Also, there's a workaround, which will allow you using non-final variables inside the anonymous interface. You should just wrap your varible with some variable holder, for example, AtomicReference:

final AtomicReference<Transform> returnTransform = new AtomicReference<>();

execute(new IExecutor() {
    @Override
    public boolean execute(Transform transform) {
        if (transform.getID() == id) {
            returnTransform.set(transform);
            return true;
        }
        return false;
    }
});

return returnTransform.get();

But this is not supposed to be idiomatic way.

Upvotes: 3

Smutje
Smutje

Reputation: 18143

Create a class implementing IExecutor which contains a field of type Transform with getter and which sets it in execute - then you can pass an object of this class to execute and getTransform afterwards.

Upvotes: 0

Related Questions