1

In the following code, the first if statement complains that current_guy can't be a final but the second if statement complains that current_guy isn't a final. I am out of ideas.

final int current_guy=0;

if (a.equals("bf")){
   current_guy=1;
}

guy1.setOnClickListener(new OnClickListener() {    
   public void onClick(View v) {

   if (current_guy==1) {
      // TODO Auto-generated method stub
   }
}
john_science
  • 6,325
  • 6
  • 43
  • 60
EGHDK
  • 17,818
  • 45
  • 129
  • 204

7 Answers7

8
final int current_guy = a.equals("bf") ? 1 : 0;
EGHDK
  • 17,818
  • 45
  • 129
  • 204
chinabuffet
  • 5,278
  • 9
  • 40
  • 64
  • How would I use this if I wanted to set it to multiple numbers? Like 1, 2, 3, 4? – EGHDK Oct 01 '12 at 19:18
  • @EGHDK A final variable **cannot** be set multiples times. It must be set *exactly once* before use. This is just how it works - or it wouldn't be final :) –  Oct 01 '12 at 19:20
  • Can I do this? `final int current_guy = a.equals("bf") ? 4 : 3 : 2 : 1 : 0` – EGHDK Oct 01 '12 at 19:22
  • you could chain the ternary operator :) it would be very difficult as far as readability is considered. – midhunhk Oct 01 '12 at 19:22
  • 2
    @EGHDK Consider this: `final int current_guy = DetermineCurrentGuy(a);` the called method can do whatever it wants - and `current_guy` will be assigned the return value once. –  Oct 01 '12 at 19:57
3

Jordan Denison had this in an answer that was deleted .. not sure why, because it is correct. This is then just a re-post for "completeness" of the current answers. (That being said, I would likely use the ternary operator approach here.)

Note that a final variable's assignment can be delayed as long as it is assigned exactly once on all code-paths before use.

final int current_guy; // no assignment here

if (a.equals("bf"))
    {
        current_guy=1;
    }
else
    {
        current_guy=0;
    }
2

You can assign current_guy to another final variable

final int finalCurrentGuy = current_guy;
guy1.setOnClickListener(new OnClickListener() {

    public void onClick(View v) {
       if (finalCurrentGuy==1) {
         ....
       }
    }

This makes copy of the variable current_guy at that point in time and passes that into the inner class

This SO post explains why it must be final inside the inner class

Community
  • 1
  • 1
RNJ
  • 15,272
  • 18
  • 86
  • 131
2

What i would do is :

int current_guy=0;

// Set the value that you want based on a condition
if (a.equals("bf"))
{
    current_guy=1;
}

final int valueToTest = current_guy;
guy1.setOnClickListener(new OnClickListener() {

public void onClick(View v) {

if (valueToTest ==1) {
    // your code
    }
}

The reason, this is imposed is because the onClick() method may execute some time later in response to an event and may be in a separate thread. Then you wont want the value of the variable to be changed either inside that handler or somewhere outside while the handler is being executed. You could say it is to prevent a dirty read of the value.

midhunhk
  • 5,560
  • 7
  • 52
  • 83
1

The reason the first one is complaining is because you can't set a final variable. The reason it's complaining that it's not final is that you're creating what is called an anonymous inner class. So your OnClickListener is a completely separate class and can't access variables from your main class at runtime. This is why it has to be Final. Then when the compiler is building your app it knows what that value is and can substitute it in there. If you want to have this variable be, well variable, then you have to pass the value into the OnClickListener so that it can get the updates as the variable changes.

CaseyB
  • 24,780
  • 14
  • 77
  • 112
  • Hmm... using your explanation, I was able to just move it outside of my `onCreate` and now it works perfectly. I thought I tried that already, but I guess not. Any disadvantage to just moving outside of `onCreate`? – EGHDK Oct 01 '12 at 19:21
  • Where did you move it to? Inside of another method? – CaseyB Oct 01 '12 at 19:25
  • It was inside of `onCreate` so I just moved it outside of that. Now it's a global variable. – EGHDK Oct 01 '12 at 19:27
  • 3
    Now it is a member variable, instead of local. This will work since the anon inner class does have access to the container class (the answer is wrong to that effect). As a local variable, it doesn't actually exist at a later point when the anon class is called, thus it has to be final so the jre can do in inline replacement of its value (this part was correct). – Robin Oct 01 '12 at 20:02
0

Make another class that implements your OnClickListener and pass it the current_guy as a parameter. This will stop it from complaining about the variable not being final. You cannot reference non-final variables when declaring inner classes and methods like that.

EGHDK
  • 17,818
  • 45
  • 129
  • 204
asteri
  • 11,402
  • 13
  • 60
  • 84
-2

Once you check/adjust, assign current_guy to a final variable:

int current_guy=0;


if (a.equals("bf"))
    {
        current_guy=1;
    }

final int final_current_guy = current_guy;

guy1.setOnClickListener(new OnClickListener() {

    public void onClick(View v) {

    // TODO Auto-generated method stub
    if (final_current_guy==1) {
        }
    }

Or use one-line assignment:

final int current_guy = (a.equals("bf") ? 1 : 0);
Seva Alekseyev
  • 59,826
  • 25
  • 160
  • 281