switch
statements should allow String
s, not just int
sFrom Arnold/Gosling 3rd Edition:
The
switch
expression must be of typechar
,byte
,short
, orint
. Allcase
labels must be constant expressionsthe expressions must contain only literals or named constants initialized with constant expressionsand must be assignable to the type of theswitch
expression.
Proposal: the switch
statement should be enhanced thus:
The
switch
expression must be of typechar
,byte
,short
,int
, orString
. Allcase
labels must be constant expressionsthe expressions must contain only literals or named constants initialized with constant expressionsand must be assignable to the type of theswitch
expression. If aString
switch
expression cannot be proven by static analysis to be interned, then the compiler will generate a call to theString
'sintern()
method.
Lisp and scheme have a symbol
type (equivalent to Java's interned String
s), which programmers are accustomed to using for selector constants because symbol
s speak for themselves when displayed in a debugger or a debug printout, whereas int
s display as unexpressive numbers. The omission of String
from the set of legal switch
expressions in Java would seem to be an oversight born of the C / C++ tradition, forgetting the usefulness of the new-to-Java String
interning mechanism.
On the matter of interning the switch
expression value, the intern() method is extremely efficient for String
s that are already interned and not too costly for those that are not. I claim it is reasonable to expect a programmer sensitive to maximal efficiency to ensure that all String
values passed into a switch
expression are already interned, but even if they are not, the performance penalty for trivial-case interning or even for nontrivial-case interning is not grave enough to kill the proposed String
switch
feature.
In comparing execution efficiency between an int
switch
statement and a String
switch
statement, three cases are relevant:
switch
statementIf there are enough int
case
statements to warrant, and if their values are sufficiently packed, the compiler can generate a table lookup to control the flow of execution. This is not possible with String
s and thus is a drawback of the proposal; however, Case 2 can always be used in place of Case 1. This drawback is not important enough to make the String
switch
statement undesirable.
switch
statementIf the cases of the switch
statement do not qualify for a table lookup but are numerous enough to warrant, some compilers may choose to transform the switch
into a hash table lookup. This technique would work as well with interned String
s as with int
s.
switch
statementIf the cases of a switch
statement do not qualify for Case 1 or Case 2, then the switch
statement degenerates into a simple if-else-if chain of equality tests, for which interned String
s are as speed-efficient as int
s.
String state variety = condition ? "fish" : "fowl";
switch (variety) {
case "fish":
return 1;
case "fowl":
return 2;
}
return 3;
In Example 1, it's clear from path analysis that variety
can evaluate only to one of two String
constants, and since String
constants are always interned, the compiler doesn't generate code to intern the switch
expression's String
value.
public int animalNumber(String variety) {
switch (variety) {
case "fish":
return 1;
case "fowl":
return 2;
}
return 3;
}
In Example 2, it could easily be beyond the compiler's ability to know if the variety
variable will have been interned before being passed to animalNumber
, so the compiler inserts a call to intern()
in the compiled code, as if the source had been written this:
switch (variety.intern()) {
The alternative would be for the compiler to complain that intern()
must be called on the switch
expression value and leave it to the programmer to call it explicitly. I think that choice would be inelegant, but others may have a different opinion.
Update: Java 5 now has enum
s, which can be used in switch
statements. This is great, but why not also allow String
?