is there a workaround for when using a foreach loop to iterate though an arraylist to not make the instance a final?

StackOverflow https://stackoverflow.com/questions/18171894

Question

So when I iterate through my array list of Buttons I'm trying to set all of their onClickedListener()/onFocusChangedListener() but when it comes to modifying of altering the button in the array list it tells me it has to be final.

Code:

        for(Button aBtn : menu_Buttons)
    {
        aBtn.setOnFocusChangeListener(new OnFocusChangeListener(){

            @Override
            public void onFocusChange(View arg0, boolean changed) {
                Log.i("LC", "focus changed");
                if(changed)
                 {
                    aBtn.setTextColor(Color.parseColor("#FFFFFF"));
                     Log.i("LC", "true");
                 }
                 else
                 {
                     aBtn.setTextColor(Color.parseColor("#CD6839"));
                     Log.i("LC", "false");
                 }
            }
        });
    }

SO it asks it to be like this instead.

for(final Button aBtn : menu_Buttons)

Can someone explain this to me, I'm not working at 100% just now and I can't see why it would have to be final.

I have found other ways to iterate through the array list using other methods but this is just bugging me.

Was it helpful?

Solution

Let's step back and look what's going on here:

  1. you have an instance variable (Button aBtn)
  2. you are referencing this instance variable in an inner class (new OnFocusChangeListener(){...})

Now, what's important to remember here is that the inner class's methods will be called at an undefined later date. So the methods contained in it is separate from the current flow of execution. Now imagine the following code:

   for(Button aBtn : menu_Buttons)
{
    aBtn.setOnFocusChangeListener(new OnFocusChangeListener(){

        @Override
        public void onFocusChange(View arg0, boolean changed) {
            Log.i("LC", "focus changed");
            if(changed)
             {
                aBtn.setTextColor(Color.parseColor("#FFFFFF"));
                 Log.i("LC", "true");
             }
             else
             {
                 aBtn.setTextColor(Color.parseColor("#CD6839"));
                 Log.i("LC", "false");
             }
        }
    });

   if(someCondition) {
      aBtn = someOtherButton;
   }
}

In this case aBtn is changed, so which Button instance should the inner class be using when one of its method is called? No matter which one the compiler chooses, it bound to produce ambiguity to the programmer, which in turn would easily become a source of subtle and hard to trace bug.

By forcing final on an instance variable being referenced in an inner class, the compiler removed this ambiguity and makes coding correct programs easier.

OTHER TIPS

The final keyword means that you can't change the value of the variable within its scope. For your loop example, you can think of the variable going out of scope at the bottom of the loop, then coming back into scope with a new value at the top of the loop. Assigning to the variable within the loop won't work.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top