views:

410

answers:

6

While using Java's switch case, it excepts only char and int, but I want to provide string cases. How to make this possible?

+1  A: 

switch-case is a language construct that is designed to accept only integral values. You cannot change the way it works.

Amarghosh
Unfortunate, really. Works in other languages.
Mark
@Mark - **some** other languages. I could list a number of languages where it does not!
Stephen C
@Mark works in javascript, actionscript etc, doesn't work in C, Java - is it safe to say the distinction is compiled vs scripting?
Amarghosh
Works in C# as well. Maybe the distinction is ECMA.
Pete Kirkham
+5  A: 

You cannot have strings in a switch-case (yet). It's on its way in Java 7.

The current types that it accepts include char, byte, short, int, Character, Byte, Short, Integer, or an enum type.

From the Java Language Specification:

The type of the Expression must be char, byte, short, int, Character, Byte, Short, Integer, or an enum type (§8.9), or a compile-time error occurs.

...

All of the following must be true, or a compile-time error will result:

  • Every case constant expression associated with a switch statement must be assignable (§5.2) to the type of the switch Expression.
  • No switch label is null.
  • No two of the case constant expressions associated with a switch statement may have the same value.
  • At most one default label may be associated with the same switch statement.
aioobe
+3  A: 

As other replies have stated, Java (currently) does not support switching on String values. There are three commonly used approaches for achieving the same effect:

  • Replace the switch with a chain of if ... else if ... statements. (Yuck).

  • Create and populate a HashMap that maps the strings to integer codes and then switch on the codes.

  • Define an enum type whose values have names that are the same as the Strings, use EType.valueOf(String) to map the strings to enum values, and switch on the enum values. (It may be more complicated if you are required to obey the Java identifier style rules for the enum values, or if the strings contain non-identifier characters.)

  • @Pete Kirkham adds the "classic hack" of switching on the hashcode of the String. However, there are a couple of problems with that:

    1. It doesn't correctly deal with the case where the supplied string is not one of the required strings. (Think: many strings hash to the same hashcode.)

    2. The hashcodes will most likely be widely spaced, so the JIT compiler will have to compile the switch as a sequence of test / branches based on the hashcode values. That is faster than test / branches based on String.equals(), but it is O(N) ... versus O(1) for a switch that compiles to a jump table.

Stephen C
You forgot the classic hack of switching on the hashcode of the string.
Pete Kirkham
doesn't the switch statement compile to a hash map or something like that anyway?
pxl
Personally, I've nver considered if/elseif chains to be in any way "Yuck".
Michael Borgwardt
@pxl - Don't think so. Switches are very low level if I recall correctly... basically the equivalent of a goto. Yes, just checked... it's a fancy goto. I'm pretty sure I've seen people do crazy (as in crazy showing off) stuff with switches.
CurtainDog
@CurtainDog - the JIT compiler will either generate a branch table or a sequence of test-and-branches, depending on the density of the (integral) label values.
Stephen C
A: 

I you're really desperate you could switch on the String's digest. If you're into that sort of thing that is.

import java.util.zip.Adler32;

public class StringSwitch {

    public static void main(String[] args) {

        String arg;
        if (args == null || args.length == 0) {
            arg = "stackoverflow";
        } else {
            arg = args[0];
        }

        Adler32 algorithm = new Adler32();
        algorithm.update(arg.getBytes());
        int hash = (int) algorithm.getValue();

        switch (hash) {
        case 647693707:
            System.out.println("Programming Q & A");
            break;
        case 145556093:
            System.out.println("Narwhals and bacon");
            break;
        case 193790704:
            System.out.println("How do they work?");
            break;
        }
    }
}
Adriaan Koster
+2  A: 

What can I switch on?

As of Java 6, you can only switch on the following types:

JLS 14.11 The switch statement

SwitchStatement:
    switch ( Expression ) SwitchBlock

The type of the Expression must be char, byte, short, int, Character, Byte, Short, Integer, or an enum type, or a compile-time error occurs. [...] Every case constant expression associated with a switch statement must be assignable to the type of the switch Expression.


So what can I do?

Depending on your use case, you may be able to use enum instead of String. Unlike String, you can switch on an enum. Here's an example:

public class EnumSwitchSample {
    static enum Color {
        BLACK, WHITE;
    }
    public static void main(String[] args) {
        test(Color.valueOf("BLACK"));
        // "It's black!"

        test(Color.WHITE);
        // "It's white!"
    }
    static void test(Color c) {
        switch (c) {
            case BLACK:
                System.out.println("It's black!");
                break;
            case WHITE:
                System.out.println("It's white!");
                break;
        }       
    }
}

However, enum in Java is actually quite powerful, and you may not even need to switch on it. Here's an example:

public class EnumMemberExample {
    static enum Mood {
        SCREAM("I'M LOUD AND OBNOXIOUS!!!") {
            @Override public String say(String statement) {
                return statement.toUpperCase().replaceAll("!", "!!!");
            }
        },
        WHISPER("Ssh... Be vewy vewy quiet...") {
            @Override public String say(String statement) {
                return statement.toLowerCase().replaceAll("!", "...");
            }
        };          
        final String msg;
        Mood(String msg)    { this.msg = msg; }
        String getMessage() { return msg; }
        abstract String say(String statement);
    }
    public static void main(String[] args) {
        test(Mood.SCREAM);
        // "I'M LOUD AND OBNOXIOUS!!!"
        // "HELLO!!! HOW ARE YOU!!!"

        test(Mood.WHISPER);
        // "Ssh... Be vewy vewy quiet..."
        // "hello... how are you..."
    }
    static void test(Mood m) {
        System.out.println(m.getMessage());
        System.out.println(m.say("Hello! How are you!"));
    }
}

See also

Related questions

polygenelubricants
A: 

Let me put my dogmatic hat on (and you're coding in Java so I'm assuming you care about OOP)

Rather than asking: how do I do the wrong thing? instead ask: what is the right thing to do? In this case: http://www.refactoring.com/catalog/replaceConditionalWithPolymorphism.html and for some discussion: http://www.c2.com/cgi/wiki?ReplaceConditionalWithPolymorphism

CurtainDog