Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Why can't I switch on a String in Java?

Is this functionality going to be put into a later Java version?

Can someone point me to an article, or themselves explain why I can't do this, as in, the technical way Java's switch statement works?

share|improve this question
48  
It's in SE 7. 16 yrs after it's request. download.oracle.com/javase/tutorial/java/nutsandbolts/… – giulio Jul 21 '11 at 6:54

9 Answers

up vote 371 down vote accepted

Switch statements with String cases have been implemented in Java SE 7, at least 16 years after they were first requested. A clear reason for the delay was not provided, but it likely had to do with performance.

Implementation in JDK 7

The feature has now been implemented in javac with a "de-sugaring" process; a clean, high-level syntax using String constants in case declarations is expanded at compile-time into more complex code following a pattern. The resulting code uses JVM instructions that have always existed.

A switch with String cases is translated into two switches during compilation. The first maps each string to a unique integer—its position in the original switch. This is done by first switching on the hash code of the label. The corresponding case is an if statement that tests string equality; if there are collisions on the hash, the test is a cascading if-else-if. The second switch mirrors that in the original source code, but substitutes the case labels with their corresponding positions. This two-step process makes it easy to preserve the flow control of the original switch.

Switches in the JVM

For more technical depth on switch, you can refer to the JVM Specification, where the compilation of switch statements is described. In a nutshell, there are two different JVM instructions that can be used for a switch, depending on the sparsity of the constants used by the cases. Both depend on using integer constants for each case to execute efficiently.

If the constants are dense, they are used as an index (after subtracting the lowest value) into a table of instruction pointers—the tableswitch instruction.

If the constants are sparse, a binary search for the correct case is performed—the lookupswitch instruction.

In de-sugaring a switch on String objects, both instructions are likely to be used. The lookupswitch is suitable for the first switch on hash codes to find the original position of the case. The resulting ordinal is a natural fit for a tableswitch.

Both instructions require the integer constants assigned to each case to be sorted at compile time. At runtime, while the O(1) performance of tableswitch generally appears better than the O(log(n)) performance of lookupswitch, it requires some analysis to determine whether the table is dense enough to justify the space–time tradeoff. Bill Venners wrote a great article that covers this in more detail, along with an under-the-hood look at other Java flow control instructions.

Before JDK 7

Prior to JDK 7, enum could approximate a String-based switch. This uses the static valueOf method generated by the compiler on every enum type. For example:

Pill p = Pill.valueOf(str);
switch(p) {
  case RED:  pop();  break;
  case BLUE: push(); break;
}
share|improve this answer
11  
It might be faster to just use If-Else-If instead of a hash for a string based switch. I have found dictionaries to be quite expensive when only storing a few items. – Jonathan Allen Dec 5 '08 at 7:17
14  
An if-elseif-elseif-elseif-else might be faster, but I'd take the cleaner code 99 times times out of 100. Strings, being immutable, cache their hash code, so "computing" the hash is fast. One would have to profile code to determine what benefit there is. – erickson Dec 5 '08 at 17:06
7  
The reason given against adding switch(String) is that it wouldn't meet the performance guarantees expects from switch() statements. They didn't want to "mislead" developers. Frankly I don't think they should guarantee the performance of switch() to begin with. – Gili Dec 22 '08 at 22:15
81  
+1 for the red-blue pills – Roopesh Shenoy Apr 7 '11 at 7:45
12  
@Bill: I see. That's a really stupid design choice; I've taken the time over a couple of years to enhance my answer and keep it up-to-date... increasing my ownership, not ceding it to the community. Now I find that I'm penalized for doing so. I understand you can't do anything about it. I'll just have to be careful not to make the same mistake again. – erickson Aug 30 '11 at 15:38
show 8 more comments

If you have a place in your code where you can switch on a String, then it may be better to refactor the String to be an enumeration of the possible values, which you can switch on. Of course, you limit the potential values of Strings you can have to those in the enumeration, which may or may not be desired.

Of course your enumeration could have an entry for 'other', and a fromString(String) method, then you could have

ValueEnum enumval = ValueEnum.fromString(myString);
switch (enumval) {
   case MILK: lap(); break;
   case WATER: sip(); break;
   case BEER: quaff(); break;
   case OTHER: 
   default: dance(); break;
}
share|improve this answer
3  
This technique also lets you decide on issues such a case insensitivity, aliases, etc. Instead of depending on a language designer to come up with the "one size fits all" solution. – Darron Dec 3 '08 at 21:12
1  
Agree with JeeBee, if you are switching on strings probably need an enum . The string usually represents something going to an interface (user or otherwise) that may or not change in the future so better replace it with enums – hhafez Dec 3 '08 at 23:24
10  
See xefer.com/2006/12/switchonstring for a nice write-up of this method. – David Schmitt Apr 14 '10 at 9:04

The following is a complete example based on JeeBee's post, using java enum's instead of using a custom method.

Note that in Java SE 7 and later you can use a String object in the switch statement's expression instead.

public class Main {

    /**
    * @param args the command line arguments
    */
    public static void main(String[] args) {

      String current = args[0];
      Days currentDay = Days.valueOf(current.toUpperCase());

      switch (currentDay) {
          case MONDAY:
          case TUESDAY:
          case WEDNESDAY:
              System.out.println("boring");
              break;
          case THURSDAY:
              System.out.println("getting better");
              case FRIDAY:
          case SATURDAY:
          case SUNDAY:
              System.out.println("much better");
              break;

      }
  }

  public enum Days {

    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY
  }
}
share|improve this answer
2  
Big thanks Thulani, this was super-helpful – Alex Dean May 23 '12 at 12:57
Is working to me. Thanks. – Julián Apr 16 at 8:35

Switches based on integers can be optimized to very efficent code. Switches based on other data type can only be compiled to a series of if() statements.

For that reason C & C++ only allow switches on integer types, since it was pointless with other types.

The designers of C# decided that the style was important, even if there was no advantage.

The designers of Java apparently thought like the designers of C.

share|improve this answer
10  
Switches based on any hashable object may be implemented very efficiently using a hash table – see .NET. So your reason isn't completely correct. – Konrad Rudolph Dec 3 '08 at 18:36
Yeah, and this is the thing I don't understand. Are they afraid hashing objects will, in the long run, become too expensive? – Alex Beardsley Dec 3 '08 at 18:41
@Nalandial: actually, with a little effort on the part of the compiler, it's not expensive at all because when the set of strings is known, it's pretty easy to generate a perfect hash (this isn't done by .NET, though; probably not worth the effort, either). – Konrad Rudolph Dec 3 '08 at 20:53
1  
@Nalandial & @Konrad Rudolph - While hashing a String (due to it's immutable nature) seems like a solution to this problem you have to remember that all non-final Objects can have their hashing functions overridden. This makes it difficult at compile time to ensure consistency in a switch. – martinatime Dec 3 '08 at 22:01
1  
You can also construct a DFA to match the string (like regular expression engines do). Possibly even more efficient than hashing. – Nate C-K Aug 22 '11 at 17:30
show 5 more comments

James Curran succinctly says: "Switches based on integers can be optimized to very efficent code. Switches based on other data type can only be compiled to a series of if() statements. For that reason C & C++ only allow switches on integer types, since it was pointless with other types."

My opinion, and it's only that, is that as soon as you start switching on non-primitives you need to start thinking about "equals" versus "==". Firstly comparing two strings can be a fairly lengthy procedure, adding to the performance problems that are mentioned above. Secondly if there is switching on strings there will be demand for switching on strings ignoring case, switching on strings considering/ignoring locale,switching on strings based on regex.... I would approve of a decision that saved a lot of time for the language developers at the cost of a small amount of time for programmers.

share|improve this answer
1  
+1 for switching based on regex. sure sounds like a cool language feature. – Robert Mar 18 '12 at 15:23
Technically, regexes already "switch", as they are basically just state machines; they merely have only two "cases", matched and not matched. (Not taking into account things like [named] groups/etc., though.) – JAB Jul 30 '12 at 17:35

will be added in version 7 of Java (February 2010).

share|improve this answer

Beside the above good arguments, I will add that lot of people today see switch as an obsolete remainder of procedural past of Java (back to C times).

I don't fully share this opinion, I think switch can have its usefulness in some cases, at least because of its speed, and anyway it is better than some series of cascading numerical else if I saw in some code...

But indeed, it is worth looking at the case where you need a switch, and see if it cannot be replaced by something more OO. For example enums in Java 1.5+, perhaps HashTable or some other collection (sometime I regret we don't have (anonymous) functions as first class citizen, as in Lua — which doesn't have switch — or JavaScript) or even polymorphism.

share|improve this answer

Reminds me of this thread : http://groups.google.com/group/comp.lang.java.programmer/browse_thread/thread/ddee6c336894e00d

share|improve this answer
4  
Ah, Jon Skeet is already there! (in 2001...) – PhiLho Dec 3 '08 at 21:47

Its a breeze in Groovy; I embed the groovy jar and create a groovy utility class to do all this thing and more which I find 'exasperating' to do in Java( since I am stuck using Java 6 in the enterprise.)

it.'p'.each{
switch ([email protected]()){
   case "choclate":
     myholder.myval=(it.text());
     break;
     }}...
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.