问题
So, I am working on this class that has a few static constants:
public abstract class Foo {
...
public static final int BAR;
public static final int BAZ;
public static final int BAM;
...
}
Then, I would like a way to get a relevant string based on the constant:
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\";
}
}
However, when I compile, I get a constant expression required
error on each of the 3 case labels.
I understand that the compiler needs the expression to be known at compile time to compile a switch, but why isn\'t Foo.BA_
constant?
回答1:
I understand that the compiler needs the expression to be known at compile time to compile a switch, but why isn't Foo.BA_ constant?
While they are constant from the perspective of any code that executes after the fields have been initialized, they are not a compile time constant in the sense required by the JLS; see §15.28 Constant Expressions for the specification of a constant expression1. This refers to §4.12.4 Final Variables which defines a "constant variable" as follows:
We call a variable, of primitive type or type String, that is final and initialized with a compile-time constant expression (§15.28) a constant variable. Whether a variable is a constant variable or not may have implications with respect to class initialization (§12.4.1), binary compatibility (§13.1, §13.4.9) and definite assignment (§16).
In your example, the Foo.BA* variables do not have initializers, and hence do not qualify as "constant variables". The fix is simple; change the Foo.BA* variable declarations to have initializers that are compile-time constant expressions.
In other examples (where the initializers are already compile-time constant expressions), declaring the variable as final
may be what is needed.
You could change your code to use an enum
rather than int
constants, but that brings another couple of different restrictions:
- You must include a
default
case, even if you havecase
for every known value of theenum
; see Why is default required for a switch on an enum? - The
case
labels must all be explicitenum
values, not expressions that evaluate toenum
values.
1 - The constant expression restrictions can be summarized as follows. Constant expressions a) can use primitive types and String
only, b) allow primaries that are literals (apart from null
) and constant variables only, c) allow constant expressions possibly parenthesised as subexpressions, d) allow operators except for assignment operators, ++
, --
or instanceof
, and e) allow type casts to primitive types or String
only.
Note that this doesn't include any form of method or lambda calls, new
, .class
. .length
or array subscripting. Furthermore, any use of array values, enum
values, values of primitive wrapper types, boxing and unboxing are all excluded because of a).
回答2:
You get Constant expression required because you left the values off your constants. Try:
public abstract class Foo {
...
public static final int BAR=0;
public static final int BAZ=1;
public static final int BAM=2;
...
}
回答3:
I got this error on Android, and my solution was just to use:
public static final int TAKE_PICTURE = 1;
instead of
public static int TAKE_PICTURE = 1;
回答4:
Because those are not compile time constants. Consider the following valid code:
public static final int BAR = new Random().nextInt();
You can only know the value of BAR
in runtime.
回答5:
You can use an enum like in this example:
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: Switch statement with enum
回答6:
This was answered ages ago and probably not relevant, but just in case.
When I was confronted with this issue, I simply used an if
statement instead of switch
, it solved the error.
It is of course a workaround and probably not the "right" solution, but in my case it was just enough.
回答7:
Sometimes the switch variable can also make that error for example:
switch(view.getTag()) {//which is an Object type
case 0://will give compiler error that says Constant expression required
//...
}
To solve you should cast the variable to int(in this case). So:
switch((int)view.getTag()) {//will be int
case 0: //No Error
//...
}
回答8:
Got this error in Android while doing something like this:
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
}
despite declaring a constant:
public static final String ADMIN_CONSTANT= "Admin";
I resolved the issue by changing my code to this:
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:
In my case, I was getting this exception because
switch (tipoWebServ) {
case VariablesKmDialog.OBTENER_KM:
resultObtenerKm(result);
break;
case var.MODIFICAR_KM:
resultModificarKm(result);
break;
}
in the second case I was calling the constant from the instance var.MODIFICAR_KM:
but I should use VariablesKmDialog.OBTENER_KM
directly from the class.
回答10:
If you're using it in a switch case then you need to get the type of the enum even before you plug that value in the switch. For instance :
SomeEnum someEnum = SomeEnum.values()[1];
switch (someEnum) {
case GRAPES:
case BANANA: ...
And the enum is like:
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:
Below code is self-explanatory, We can use an enum with a switch case:
/**
*
*/
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;
}
}
Based on the class values from the enum can be mapped:
switch (ClassNames.valueOf(clazz.getSimpleName())) {
case STRING:
String castValue = (String) keyValue;
break;
case BOOLEAN:
break;
case Integer:
break;
case LONG:
break;
default:
isValid = false;
}
Hope it helps :)
回答12:
I recommend you to use enums :)
Check this out:
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;
}
}
Then you can use it like this:
System.out.println(Foo.BAR.getDescription());
来源:https://stackoverflow.com/questions/3827393/java-switch-statement-constant-expression-required-but-it-is-constant