views:

156

answers:

4

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?

+7  A: 

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 a definition of what is required of a constant expression. 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.

Stephen C
Yep, that was it. I forgot initializers. But still, good to learn something out of that mistake :D Thanks.
Austin Hyde
You should try with enums
Suresh S
@Suresh S - yes, that is another alternative. But in terms of lines of code changed, adding initializers is simpler.
Stephen C
A: 

No, static final is not a constant. It is a static variable where the value cannot be changed.

For constant, it should be (if I remember right, it's quite some time since I last did Java):

public const int BAR = 0;

You should also assign some value, else BAR == BAZ == BAM.

Amry
No `const` in Java--`static final` is as good as it gets. But "value cannot be changed" (after initialization) is right.
Michael Brewer-Davis
*static final is as good as it gets* no, using an enum is as good as it gets.
seanizer
Sorry. Don't quite remember what Java can do. I am mostly active using C# not so probably I mixed C# `const` into Java. :)
Amry
+1  A: 

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.

Sheldon L. Cooper
Interesting. Would `public static final int BAR = new Random().nextInt()` work?
Thilo
Yes, it does. Thanks.
Sheldon L. Cooper
Thilo's statement compiles but the switch statement complains _constant expression required_. Further, couldn't two consecutive `new Random().nextInt()` return the same values?
Tony Ennis
@Tony: Which is a good thing. It does not compile because it is not initialized with a compile-time constant. See Stephen's accepted answer. If that did compile, a random integer would be hard-coded into the class, with quite unpredictable results.
Thilo
I'm surprised the constant in the switch is rejected, and the 'constant' itself isn't. I never would of thought it would be this way. Of course, it isn't truly a constant I suppose.
Tony Ennis
+2  A: 

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;
    ...
}
Tony Ennis