1

I've looked at other questions and still can't figure it out. Why won't it let me compile this code with a switch statement? I get error that typical error "case expressions must be constant expressions". I am trying to switch on byte from a message. I want to use the switch due to speed issues and try not to do any conversions i.e. from int to byte. My Utils class contains an enum PID with A,B,C...in it. I want to switch on these but the message I get back is in bytes.

public class SomeClass extends Thread {
    public static final byte myCase1 = (byte) Utils.PID.A.ordinal();
    public static final byte myCase2 = (byte) Utils.PID.B.ordinal();
    public static final byte myCase3 = (byte) Utils.PID.C.ordinal();

    private double[] findAllData(ByteBuffer message) {

        byte[] byteBuffer = new byte[9000];
        // parse through and find all PIDs
        for(int i=0 ;i < message.capacity(); i++) {
            message.position(i);

            switch (message.get(i)) {
            case myCase1 : break;  // Compiler errors at the case statements
            case myCase2 : break;// Compiler errors at the case statements
            case myCase3 : break;// Compiler errors at the case statements
            }
    }
}


//  Utility class
public class Utils {
    public enum PID { A,B,C };
}
JPM
  • 9,077
  • 13
  • 78
  • 137
  • 1
    This was discussed also here: http://stackoverflow.com/questions/3827393/java-switch-statement-constant-expression-required-but-it-is-constant – Tudor Nov 14 '11 at 17:28
  • Duplicate to http://stackoverflow.com/questions/1155409/final-public-static-ints-cant-be-used-in-a-switch-statement – Jarno Argillander Nov 14 '11 at 17:31
  • Please remember to always post your complete error message when posting about a compiler error, or the stack trace when asking about a run-time exception being thrown. – Hovercraft Full Of Eels Nov 14 '11 at 17:35
  • @JPM: There's absolutely no way your edited example compiles. You're trying to set a `static final` field in an instance constructor which is not allowed. So I don't think anyone can explain "why it works" since it quite obviously doesn't. – Mark Peters Nov 14 '11 at 19:18

2 Answers2

4

Even though myCase1 is a constant it is not a constant known at compile time.

Instead I would switch on the enum

private static final Utils.PID[] PIDS = Utils.PID.values();

private double[] findAllData(ByteBuffer message) {

    byte[] byteBuffer = new byte[9000];
    // parse through and find all PIDs
    for (int i = 0; i < message.capacity(); i++) {
        message.position(i);

        switch (PIDS[message.get(i)]) {
            case A:
                break;
            case B:
                break;
            case C:
                break;
        }
    }

e.g. This is not going to work

private static final int NUM1 = Integer.getInteger("num1"); // from command line properties
private static final int NUM2 = Integer.getInteger("num2"); // from command line properties

switch(num) {
  case NUM1: break;
  case NUM2: break;
}
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • So explain to me why it will work when you don't set it in the class but set it at run time in the constructor but the compiler is fine with it? See above edit in question – JPM Nov 14 '11 at 17:58
  • @JPM: Your example is broken, see my comment on your question. – Mark Peters Nov 14 '11 at 19:19
  • Hmm must be bug in Eclipse...shows fine in the editor but when I clean code it errors. removed that code example. Your example does work, but makes me wonder why compiler can't handle it,seems simple enough for compiler. But that is probably another discussion for say the wiki. – JPM Nov 14 '11 at 19:29
  • @JPM, Its simple in theory, but its rather complex in practice as the compiler doesn't make any assumption about what a method call returns. e.g. Object.getClass() returns `Class>` rather than `Class` i.e. the compiler doesn't have any idea what this method returns even though it knows the type of reference it is called on. – Peter Lawrey Nov 15 '11 at 08:08
2

case statements have to be compile-time constants. You need to pre-calculate (byte) Utils.PID.A.ordinal(); (and the other two constants) and then hard-code their values.

Kylos
  • 1,888
  • 14
  • 24
  • Isn't that what I am doing when class is instantiated the constants are created by these lines, static final byte myCase3 = (byte) Utils.PID.C.ordinal(); – JPM Nov 14 '11 at 17:32
  • @JPM, Its too complicated for the compiler to evaluate. See my example. – Peter Lawrey Nov 14 '11 at 17:35
  • JPM, that happens at runtime. The case values have to be constant when you compile the file. – Kylos Nov 14 '11 at 17:42