Изменение значения параметра в JButton ActionEvent возвращает ошибку, должно быть окончательным или фактически окончательным

Я пытаюсь создать функцию, которая создает JButton. Кнопка увеличивает или уменьшает значение R, G или B (красный, зеленый, синий). Пользователь вводит несколько параметров,

  • родитель кнопок (JPanel)
  • Текст на кнопке (String)
  • Функция кнопки либо увеличить, либо уменьшить (логическое значение)
  • Значение цвета, которое пользователь хочет изменить (int)

Поэтому, если пользователь хочет увеличить зеленый цвет, целочисленное значение userGreen должно увеличиться на 15. Однако, когда я попытался увеличить его, я получил сообщение об ошибке:

Локальная переменная userRed, определенная во внешней области видимости, должна быть окончательной или действительно окончательной.

Моя фактическая программа имеет много переменных и других присоединенных функций, и присоединение всей программы было бы слишком длинным, поэтому я сделал самый короткий пример, какой только мог. В этом примере просто подсчитывается количество нажатий кнопки и выводится на консоль.

Это выдает ту же ошибку

Локальная переменная clickNumber, определенная во внешней области, должна быть окончательной или действительно окончательной.

Можно ли изменить значение параметра в прослушивателе действий JButton? И почему переменная должна быть final?

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class ButtonTest {
    int clickNumber = 0;
    
    public ButtonTest() {
        JFrame frame = new JFrame("Button Test");
        frame.add(newButton(frame, "Click me", clickNumber));
        frame.pack();
        frame.setVisible(true);
    }

    private JButton newButton(JFrame parent, String text, int clickNumber) {
        JButton btn = new JButton(text);
        btn.setBackground(Color.WHITE);
        
        btn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println(clickNumber); //error here, "Local variable clickNumber defined in an enclosing scope must be final or effectively final"
            }
        });
        clickNumber += 1; // if i remove this than the error goes away, so changing the value of the variable is somehow related
        
        parent.add(btn);
        return btn;
    }
    
    public static void main(String[] args) {
        try {
            String laf = UIManager.getCrossPlatformLookAndFeelClassName();
            UIManager.setLookAndFeel(laf);
        } 
        catch (Exception e) {}

        SwingUtilities.invokeLater(new Runnable(){
            public void run() {
                new ButtonTest();
            }
        });
    }
}

person CodingNinja    schedule 03.11.2020    source источник


Ответы (1)


Вы не можете получить доступ к переменной в локальном классе, если вы измените ее вне его. Вот что говорит об этом JLS (Java 11, пункт 8.1.3):

Любая локальная переменная, формальный параметр или параметр исключения, используемые, но не объявленные во внутреннем классе, должны быть либо объявлены окончательными, либо фактически окончательными (§4.12.4), иначе при попытке использования возникает ошибка времени компиляции.

Ссылка: https://docs.oracle.com/javase/specs/jls/se11/html/jls-8.html#jls-8.1.3


UPD: Если вам нужен обходной путь, вы можете попробовать это:

int finalWorkaround = clickNumber; 

btn.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // Our finalWorkaround is effectively final here, so we can use it
        System.out.println(finalWorkaround);
    }
});
clickNumber += 1;
person nkrivenko    schedule 03.11.2020
comment
Спасибо! Этот обходной путь должен работать. Можете ли вы объяснить, почему массив int является окончательным? - person CodingNinja; 04.11.2020
comment
Вы не меняете finalWorkaround в методе (вы никогда не присваиваете значение этой переменной), поэтому он фактически является окончательным. - person nkrivenko; 04.11.2020
comment
clickNumber не является фактически окончательным, потому что вы присваиваете ему значение. - person nkrivenko; 04.11.2020
comment
Если ответ полезен, не могли бы вы отметить его как принятый? - person nkrivenko; 04.11.2020
comment
Хотел сделать это раньше, извините. Принятый! - person CodingNinja; 04.11.2020