Оператор переключения Java: требуется постоянное выражение, но оно является постоянным - PullRequest
148 голосов
/ 30 сентября 2010

Итак, я работаю над этим классом, который имеет несколько статических констант:

public abstract class Foo {
    ...
    public static final int BAR;
    public static final int BAZ;
    public static final int BAM;
    ...
}

Затем я хотел бы получить способ получить соответствующую строку на основе константы:

public static String lookup(int constant) {
    switch (constant) {
        case Foo.BAR: return "bar";
        case Foo.BAZ: return "baz";
        case Foo.BAM: return "bam";
        default: return "unknown";
    }
}

Однако, когда я компилирую, я получаю ошибку constant expression required на каждой из 3 меток регистра.

Я понимаю, что компилятору необходимо знать выражение во время компиляции для компиляции переключателя, нопочему не Foo.BA_ константа?

Ответы [ 10 ]

135 голосов
/ 30 сентября 2010

Я понимаю, что для компиляции переключателя необходимо, чтобы выражение было известно во время компиляции, но почему Foo.BA_ не является константой?

Хотя они постоянны с точки зрения любого кода, который выполняется после инициализации полей, они не являются постоянной времени компиляции в смысле, требуемом JLS; см. §15.28 Выражения констант для спецификации выражения констант 1 . Это относится к §4.12.4 Окончательные переменные , которые определяют «постоянную переменную» следующим образом:

Мы называем переменную примитивного типа или типа String, которая является конечной и инициализируется константным выражением времени компиляции (§15.28) постоянной переменной. Независимо от того, является ли переменная постоянной или нет, это может иметь значение в отношении инициализации класса (§12.4.1), двоичной совместимости (§13.1, §13.4.9) и определенного присваивания (§16).

В вашем примере переменные Foo.BA * не имеют инициализаторов и, следовательно, не квалифицируются как «постоянные переменные». Исправление просто; измените объявления переменных Foo.BA *, чтобы инициализаторы были константными выражениями во время компиляции.

В других примерах (где инициализаторы уже являются константными выражениями времени компиляции), объявление переменной как final может быть тем, что необходимо.

Вы можете изменить свой код, чтобы использовать enum вместо int констант, но это приносит еще пару различных ограничений:


1 - Ограничения константных выражений можно суммировать следующим образом. Выражения констант a) могут использовать типы примитивов и только String, b) разрешать основные цвета, которые являются литералами (кроме null) и только константными переменными, c) разрешать выражения констант, возможно заключенные в скобки как подвыражения, d) разрешать операторы за исключением присваивания операторы ++, -- или instanceof и e) разрешают приведение типов к примитивным типам или только String.

Обратите внимание, что это не включает в себя какие-либо методы или лямбда-вызовы, new, .class. .length или массив подписки. Кроме того, любое использование значений массива, enum значений, значений типов примитивных оболочек, упаковки и распаковки исключено из-за a).

70 голосов
/ 30 сентября 2010

Вы получаете Требуется постоянное выражение , потому что вы оставили значения вне своих констант.Попробуйте:

public abstract class Foo {
    ...
    public static final int BAR=0;
    public static final int BAZ=1;
    public static final int BAM=2;
    ...
}
41 голосов
/ 26 февраля 2015

Я получил эту ошибку на Android, и мое решение было просто использовать:

public static final int TAKE_PICTURE = 1;

вместо

public static int TAKE_PICTURE = 1;
29 голосов
/ 30 сентября 2010

Потому что это не постоянные времени компиляции.Рассмотрим следующий действительный код:

public static final int BAR = new Random().nextInt();

Вы можете знать значение BAR только во время выполнения.

17 голосов
/ 21 июля 2011

Вы можете использовать перечисление, как в этом примере:

public class MainClass {
enum Choice { Choice1, Choice2, Choice3 }
public static void main(String[] args) {
Choice ch = Choice.Choice1;

switch(ch) {
  case Choice1:
    System.out.println("Choice1 selected");
    break;
 case Choice2:
   System.out.println("Choice2 selected");
   break;
 case Choice3:
   System.out.println("Choice3 selected");
   break;
    }
  }
}

Источник: Оператор переключения с перечислением

4 голосов
/ 15 февраля 2018

На этот вопрос давным-давно ответили, и, вероятно, он не актуален, но на всякий случай. Когда я столкнулся с этой проблемой, я просто использовал оператор if вместо switch, это решило ошибку. Это, конечно, обходной путь и, возможно, не «правильное» решение, но в моем случае этого было достаточно.

0 голосов
/ 04 декабря 2018

В моем случае я получал это исключение, потому что

switch (tipoWebServ) {
                            case VariablesKmDialog.OBTENER_KM:
                                resultObtenerKm(result);
                                break;
                            case var.MODIFICAR_KM:
                                resultModificarKm(result);
                                break;
                        }

во втором случае я вызывал константу из экземпляра var.MODIFICAR_KM:, но я должен использовать VariablesKmDialog.OBTENER_KM непосредственно из класса.

0 голосов
/ 24 ноября 2018

Получил эту ошибку в Android, когда делал что-то вроде этого:

 roleSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

            switch (parent.getItemAtPosition(position)) {
                case ADMIN_CONSTANT: //Threw the error

            }

несмотря на объявление константы:

public static final String ADMIN_CONSTANT= "Admin";

Я решил проблему, изменив свойкод к этому:

roleSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
        @Override
        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {

            String selectedItem = String.valueOf(parent.getItemAtPosition(position));
            switch (selectedItem) {
                case ADMIN_CONSTANT:

            }
0 голосов
/ 14 мая 2018

Иногда переменная также может выдавать эту ошибку, например:

switch(view.getTag()) {//which is an Object type

   case 0://will give compiler error that says Constant expression required

   //...
}

Чтобы решить эту проблему, необходимо привести переменную к типу int (в данном случае)Итак:

switch((int)view.getTag()) {//will be int

   case 0: //No Error

   //...
}
0 голосов
/ 21 июля 2011

Я рекомендую вам использовать enums:)

Проверьте это:

public enum Foo 
{
    BAR("bar"),
    BAZ("baz"),
    BAM("bam");

    private final String description;

    private Foo(String description)
    {
        this.description = description;
    }

    public String getDescription()
    {
        return description;
    }
}

Тогда вы можете использовать это так:

System.out.println(Foo.BAR.getDescription());
...