The final local variable cannot be assigned
Asked Answered
A

6

37

I have an array of seats, and the array has two strings(selected and empty). On mouse click, I want to traverse the array and find the selected seat. When I press the button it says:

The final local variable seatno cannot be assigned, since it is defined in an enclosing type.

    JButton btnContinue = new JButton("Next");
    btnContinue.addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent arg0) {

            for(int x=0;x<17;x++){
                if(anArray[x]=="selected"){

                    seatno = anArray[x];
                }
            }

            data page=new data(newfrom,newto,newtime,date2,seatno);
            page.setVisible(true);
            setVisible(false);
        }
    });
    btnContinue.setBounds(358, 227, 62, 23);
    contentPane.add(btnContinue);
Anaximenes answered 15/4, 2012 at 22:0 Comment(1)
your seatno variable has the final keyword in it.Crowfoot
P
97

The point is that method-local variables from the enclosing type are actually copied to instances of anonymous classes (this is because of activation frame issues, but I won't go further into detail as this is not really relevant to the question), which is why they need to be final, because the variable in the nested type instance is not the same anymore.

So, here is the first example:

void foo() {
    int a = 3;
    new Runnable() {
        @Override
        public void run() {
            a += 3;
        }
    };
}

This does not compile, because you cannot reference a non-final variable in an anonymous class' method. When you add a final modifier to the declaration of a, the value of a would be copied into the created instance of the anonymous class you have defined. However, you will not be allowed to change the value of a, because the changes would not be visible to the method where a was declared.

However, anonymous classes are not static, that is, they have a reference to the enclosing instance (unless the method where they are declared is static) which you can use to modify variables of the enclosing instance:

int a = 3;

void foo() {
    new Runnable() {
        @Override
        public void run() {
            a += 3;
        }
    };
}

This example does compile and it would increase a by 3 every time the run() method of the anonymous class' instance is called. (In this example it is never called, but it is just an example.)

So, to summarize, you need to convert the variable seatno from a method-local variable to an instance variable of the enclosing type. Or, if it is yet, you need to remove the final modifier as final variables can only be assigned once.

Update: In Java 8, the concept of effectively final variables is introduced (see Java Language Specification). However, in the first example of this post, the variable a is assigned multiple times, which prevents it from being effectively final. This means that this example still does not compile with Java 8. (The compile error is "Local variable a defined in an enclosing scope must be final or effectively final")

Procne answered 15/4, 2012 at 22:19 Comment(0)
R
4

A final variable cannot change it's value (it's similar to const from C/C++).

You probably want to make it a field in a class (without the final keyword of course), not a local variable inside a function.

Rouge answered 15/4, 2012 at 22:3 Comment(0)
C
4

Instead of defining a class member variable you can also use a mutable int to achieve the same.

void foo() {
    final MutableInt a = new MutableInt(3);
    new Runnable() {
        @Override
        public void run() {
           a.add(3);
        }
    };
}

Since MutableInt is not primitive type (hence passed by reference) and can be reassigned this works.

Coelho answered 11/7, 2013 at 20:41 Comment(2)
Note: MutableInt requires Apache Commons Lang.Indigotin
Nice, thank You. MutableInt is more conventient than AtomicInteger, because less codesmell (less code needed)Honorific
R
2

I recently faced similar problem. In my case it was easier to create final array (or collection) and to add variable, that I wanted to change inside anonymous class, to this array, as below.

   int a = 3;
   final int[] array = new int[1];
   array[0] = a;
   new Runnable() {
       @Override
       public void run() {
           array[0] += 3;
       }
   };
Retriever answered 26/2, 2017 at 17:0 Comment(0)
P
0

Without knowing the declaration of seatno, I'd suggest to introduce a new variable in the mouseClicked() method that is not final and does the same job as seatno currently does, as the variable seems only to be used inside that method.

By the way: Capitalize your class names (data should be Data). Will look much more clear.

Pedigo answered 15/4, 2012 at 22:2 Comment(0)
C
0

Make sure your variable doesn't have the final modifier.

//final, can be set only when the object is created.
private final String seatno;

//no final modifier, the value can be set every time you "want"
private String seatno;

Also, to compare Strings you should use equals:

if(anArray[x].equals("selected"))
Crowfoot answered 15/4, 2012 at 22:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.