web-dev-qa-db-fra.com

Instruction de commutateur Java: expression constante requise, mais elle IS constant

Donc, je travaille sur cette classe qui a quelques constantes statiques:

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

Ensuite, je voudrais un moyen d'obtenir une chaîne pertinente basée sur la constante:

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

Cependant, lors de la compilation, une erreur constant expression required apparaît sur chacune des 3 étiquettes de cas.

Je comprends que le compilateur a besoin de connaître l'expression au moment de la compilation pour compiler un commutateur, mais pourquoi Foo.BA_ n'est-il pas constant?

138
Austin Hyde

Je comprends que le compilateur a besoin que l’expression soit connue au moment de la compilation pour compiler un commutateur, mais pourquoi Foo.BA_ n’est-il pas constant?

Bien qu’ils soient constants du point de vue du code qui s’exécute après l’initialisation des champs, ils ne sont pas une constante de temps de compilation au sens requis par le JLS; voir §15.28 Expressions constantes pour une définition de ce qui est requis d'une expression constante. Ceci fait référence à §4.12.4 Variables finales qui définit une "variable constante" comme suit:

Nous appelons une variable, de type primitif ou de type String, finale et initialisée avec une expression constante au moment de la compilation (§15.28), une variable constante. Le fait qu'une variable soit ou non une variable constante peut avoir des implications en ce qui concerne l'initialisation de classe (§12.4.1), la compatibilité binaire (§13.1, §13.4.9) et l'affectation définie (§16).

Dans votre exemple, les variables Foo.BA * n'ont pas d'initialiseurs et ne peuvent donc pas être qualifiées de "variables constantes". La solution est simple. changez les déclarations de variable Foo.BA * pour que les initialiseurs soient des expressions constantes au moment de la compilation.

Dans d'autres exemples (où les initialiseurs sont déjà des expressions constantes au moment de la compilation), la déclaration de la variable en tant que final peut être ce qui est nécessaire.

Et, bien sûr, vous pouvez modifier votre code pour utiliser une constante enum plutôt que int, bien que cela pose un autre problème. Si vous utilisez un enum dans un switch, vous devez inclure un cas default, même si vous avez case pour chaque valeur connue de enum; voir Pourquoi la valeur par défaut est-elle requise pour un commutateur sur une énumération dans ce code?

127
Stephen C

Vous obtenez Expression constante requise parce que vous avez laissé les valeurs de vos constantes. Essayer:

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

J'ai eu cette erreur sur Android, et ma solution était juste d'utiliser:

public static final int TAKE_PICTURE = 1;

au lieu de 

public static int TAKE_PICTURE = 1;
39
Teo Inke

Parce que ce ne sont pas des constantes de temps de compilation. Considérons le code valide suivant:

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

Vous pouvez uniquement connaître la valeur de BAR au moment de l'exécution.

27
Sheldon L. Cooper

Vous pouvez utiliser une énumération comme dans cet exemple:

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

Source: Instruction switch avec enum

17
thenosic

Cela a été répondu il y a longtemps et probablement sans objet, mais juste au cas où… __. Lorsque j'ai été confronté à ce problème, j'ai simplement utilisé une instruction if au lieu de switch, le problème a été résolu . et probablement pas la "bonne" solution, mais dans mon cas c'était juste suffisant.

0
Samer Murad

Parfois, la variable variable peut aussi commettre cette erreur, par exemple:

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

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

   //...
}

Pour résoudre ce problème, vous devez convertir la variable en int (dans ce cas). Alors:

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

   case 0: //No Error

   //...
}
0
Mahdi-Malv

Dans mon cas, je recevais cette exception parce que

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

dans le second cas, j'appelais la constante de l'instance var.MODIFICAR_KM: mais je devrais utiliser VariablesKmDialog.OBTENER_KM directement à partir de la classe.

0
Gian Gomen

Je vous recommande d'utiliser des enums :)

Regarde ça:

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

Ensuite, vous pouvez l'utiliser comme ceci:

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

Vous avez cette erreur dans Android en faisant quelque chose comme ça:

 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

            }

malgré déclarer une constante:

public static final String ADMIN_CONSTANT= "Admin";

J'ai résolu le problème en changeant mon code pour ceci:

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
ojonugwa ochalifu