4

Kind of a silly problem I'm facing here... Basically I'm in a For-loop and within this loop I'm always calling a function to make a button. But in this function I want to pass the loop iterator as it's changing to differentiate the buttons. But then it tells me I need to make the loop iterator "final" which means it doesn't change!

Well my problem will make more sense with some skeleton code:

for(int i = 0; i < appList.size(); i++) { 

                //some other stuff including creating the below button 'btn'

                btn.setOnClickListener(new View.OnClickListener() {
                    public void onClick(View v) {
                        //set some attribute based on i
                        //but when I do this it only sets based on the greatest value of i (!)
                    }
                });
}

Meh kinda silly problem I know... I'm new to Java though!

Cheers.

1
  • The comment saying you will set the attribute based on i using the greatest value of i seems inaccurate. You shouldn't be able to compile code containing your snippet due to the lack of keyword final indicated in the answers. You may have wrapped your integer in a final single element array, though, and you'd get the behavior you describe. Commented Jun 14, 2011 at 15:37

2 Answers 2

4
for(int i = 0; i < appList.size(); i++) { 

    final int _i = i;

    btn.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            // use _i instead of i
        }
    });
}
Sign up to request clarification or add additional context in comments.

1 Comment

_i must be declared final
1

Consider this bit of silly example code:

int i = 0;
obj.invokeThunkAfter10Seconds(new ThunkObject() {
    public void thunk() {
        System.out.println(i);
    }
}
i = 1;

The ThunkObject holds a reference to i, but i can change, which makes the output unpredictable and depends on when i is changed and when thunk is invoked.

Because Java doesn't have proper closures (by design, see Cannot refer to a non-final variable inside an inner class defined in a different method), you are explicitly not allowed to capture non-final (i.e. changable) variables like this.

Instead you must declare the variable final, meaning it's initialized and then is not changable. This means you can never change i after it has been captured by the inner class.

final int i = 0;
obj.invokeThunkAfter10Seconds(new ThunkObject() {
    public void thunk() {
        System.out.println(i);
    }
}
// Can't change i here. It will forever now be 0.

In your example you can't just set i to be final, because you do want to change the value on each loop iteration. Instead you can create a copy of the value in a final variable:

for(int i = 0; i < appList.size(); i++) { 
    //some other stuff including creating the below button 'btn'

    final int capturedI = i;
    btn.setOnClickListener(new View.OnClickListener() {
        public void onClick(View v) {
            //set some attribute based on capturedI
        }
    });
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.