简体   繁体   中英

Java - getting loop iterator to a function inside loop?

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.

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
        }
    });
}

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 (ie 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
        }
    });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM