Normally, default is not necessary in a switch statement. However, in the following situation the code successfully compiles only when I uncomment the default statement. Can anybody explain why?
public enum XYZ {A,B};
public static String testSwitch(XYZ xyz)
{
switch(xyz)
{
case A:
return "A";
case B:
//default:
return "B";
}
}
As has been stated, you need to return a value and the compiler doesn't assume that the enum cannot change in the future. E.g. you can create another version of the enum and use that without recompiling the method.
Note: there is a third value for
xyz
which is null.This ha the same result as
The only way to avoid a return is to throw an exception.
I think this is explained by the JLS definite assignment rules for
switch
statements (JLS 16.2.9) which states the following:If we then apply this to the notional
V
which is the return value of the method, we can see that if there is nodefault
branch, the value would be notionally unassigned.OK ... I'm extrapolating definite assignment rules to cover return values, and maybe they don't. But the fact that I couldn't find something more direct in the spec doesn't mean it isn't there :-)
There's another (more sound) reason why the compiler has to give an error. It stems from the binary compatibility rules for
enum
(JLS 13.4.26) which state the following:So how does that apply in this case? Well suppose that the compiler was allowed to infer that the OP's example switch statement always returned something. What happens if the programmer now changes the
enum
to add an extra constant? According to the JLS binary compatibility rules, we haven't broken binary compatibility. Yet the method containing theswitch
statement can now (depending on its argument) return an undefined value. That cannot be allowed to happen, so therefore the switch must be a compilation error.Because compiler cannot guess that there are only two values in the
enum
and forces you to return value from the method. (However I dont know why it cannot guess, maybe it has something with reflection).There is a contract that this method has to return a String unless it throws an Exception. And everytime is not limited to those cases where the value of
xyz
is equal toXVZ.A
orXYZ.B
.Here's another example, where it's obviuos, that the code will run correct but where we have a compiletime error for the very same reason:
It is not true that you have to add a default statement, it is true, that you have to return a value at any time. So either add a default statement or add a return statement after the switch block.
The reason that you have to uncomment the
default
is that your function says that it returns aString
, but if you only havecase
labels defined forA
andB
then the function will not return a value if you pass in anything else. Java requires that all functions that state that they return a value actually return a value on all possible control paths, and in your case the compiler isn't convinced that all possible inputs have a value returned.I believe (and I'm not sure of this) that the reason for this is that even if you cover all your
enum
cases, the code could still fail in some cases. In particular, suppose that you compile the Java code containing this switch statement (which works just fine), then later on change theenum
so that there's now a third constant - let's sayC
- but you don't recompile the code with theswitch
statement in it. Now, if you try writing Java code that uses the previously-compiled class and passes inC
into this statement, then the code won't have a value to return, violating the Java contract that all functions always return values.More technically speaking, I think the real reason is that the JVM bytecode verifier always rejects functions in which there is some control path that falls off the end of a function (see §4.9.2 of the JVM spec), and so if the code were to compile it would just get rejected by the JVM at runtime anyway. The compiler therefore gives you the error to report that a problem exists.