Оператор switch Java: требуется постоянное выражение, но оно постоянное

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

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 для каждой из трех меток case.

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

Ответ 1

  Я понимаю, что для компиляции переключателя нужно, чтобы выражение было известно во время компиляции, но почему не константа 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 - The constant expression restrictions can be summarized as follows. Constant expressions a) can use primitive types and [TG49] only, b) allow primaries that are literals (apart from [TG410]) and constant variables only, c) allow constant expressions possibly parenthesised as subexpressions, d) allow operators except for assignment operators, [TG411], [TG412] or [TG413], and e) allow type casts to primitive types or [TG414] only.

Note that this does not include any form of method or lambda calls, [TG415], [TG416]. [TG417] or array subscripting. Furthermore, any use of array values, [TG418] values, values of primitive wrapper types, boxing and unboxing are all excluded because of a).

Ответ 2

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

public abstract class Foo {
    ...
    public static final int BAR=0;
    public static final int BAZ=1;
    public static final int BAM=2;
    ...
}

Ответ 3

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

public static final int TAKE_PICTURE = 1;

вместо

public static int TAKE_PICTURE = 1;

Ответ 4

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

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

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

Ответ 5

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

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;
    }
  }
}

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

Ответ 6

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

Ответ 7

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

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

   //...
}

Ответ 8

Получил эту ошибку в 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:

            }

Ответ 9

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

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

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

Ответ 10

Если вы используете его в случае переключателя, вам нужно получить тип перечисления еще до того, как вы включите это значение в переключатель. Например:

SomeEnum someEnum = SomeEnum.values()[1];

switch (someEnum) {
            case GRAPES:
            case BANANA: ...

И перечисление выглядит так:

public enum SomeEnum {

    GRAPES("Grapes", 0),
    BANANA("Banana", 1),

    private String typeName;
    private int typeId;

    SomeEnum(String typeName, int typeId){
        this.typeName = typeName;
        this.typeId = typeId;
    }
}

Ответ 11

Код ниже говорит само за себя, Мы можем использовать enum с регистром switch:

/**
 *
 */
enum ClassNames {
    STRING(String.class, String.class.getSimpleName()),
    BOOLEAN(Boolean.class, Boolean.class.getSimpleName()),
    INTEGER(Integer.class, Integer.class.getSimpleName()),
    LONG(Long.class, Long.class.getSimpleName());
    private Class typeName;
    private String simpleName;
    ClassNames(Class typeName, String simpleName){
        this.typeName = typeName;
        this.simpleName = simpleName;
    }
}

На основе значений классов из перечисления можно отобразить:

 switch (ClassNames.valueOf(clazz.getSimpleName())) {
        case STRING:
            String castValue = (String) keyValue;
            break;
        case BOOLEAN:
            break;
        case Integer:
            break;
        case LONG:
            break;
        default:
            isValid = false;

    }

Надеюсь, это поможет :)

Ответ 12

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

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

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());