Why is it required by default to enable enumeration?

Typically, the default switch statement is not necessary. However, in the following situation, the code only compiles successfully when I uncomment the default statement. Can anyone explain why?

public enum XYZ {A,B}; public static String testSwitch(XYZ xyz) { switch(xyz) { case A: return "A"; case B: //default: return "B"; } } 
+34
java enums switch-statement default
Feb 16 '11 at 6:28
source share
7 answers

The reason you need to uncomment default is because your function says that it returns String , but if you only have case tags defined for A and B , then the function will not return if you pass something- something else. Java requires that all functions that claim to return a value do return a value in all possible control paths, and in your case, the compiler is not convinced that all possible inputs have a return value.

I believe (and I'm not sure about that) that the reason for this is that even if you cover all your enum cases, in some cases the code may still fail. In particular, suppose you compile Java code containing this switch statement (which works very well), and then change enum so that a third constant now appears - let’s say C - but you will not recompile the code with the switch . Now, if you try to write Java code that uses a previously compiled class and passes it to C in this statement, then the code will not have a return value, violating the Java contract, which all functions always return values.

From a technical point of view, I believe that the real reason is that the JVM bytecode verifier always rejects functions that have some control path that falls from the end of the function (see section 4.9.2 of the JVM specification ), and therefore if the code was to be compiled, it would still be rejected by the JVM at runtime. Therefore, the compiler reports an error indicating a problem.

+40
Feb 16 '11 at 6:32
source share

I think this is due to the specific JLS assignment rules for switch ( JLS 16.2.9 ), which say the following:

"V [un] is assigned after the switch statement if all of the following is true:

  • Either there is a default label in the switch block, or V is assigned [un] after the switch expression.

If we then apply this to a conditional V which is the return value of the method, we will see that if there is no branch by default , the value will be conditionally not assigned.

OK ... I extrapolate certain assignment rules to cover the return values, and maybe they don't. But the fact that I could not find something more direct in the specification does not mean that it is not there :-)




There is one more (more justified) reason why the compiler should throw an error. It follows from the binary compatibility rules for enum ( JLS 13.4.26 ), which state the following:

"Adding or reordering constants of type enum will not compromise compatibility with existing binaries."

So how is this applicable in this case? Well, suppose the compiler was allowed to conclude that the OP example switch statement always returned something. What happens if the programmer now changes enum adding an additional constant? According to the JLS binary compatibility rules, we did not violate binary compatibility. However, a method containing a switch can now (depending on its argument) return an undefined value. This cannot be allowed, so switching should be a compilation error.




In Java 12, switch enhancements have been introduced, including switch expressions. This faces the same problem with enumerations that vary between compile time and runtime. According to JEP 354 , they solve this problem as follows:

The cases of the switch statement must be exhaustive; for all possible values ​​there must be an appropriate switch label. (Obviously, switch statements do not have to be exhaustive.)

In practice, this usually means that a default condition is required; however, in the case of an enumeration switch expression that encompasses all known constants, the compiler inserts a default clause to indicate that the enumeration definition has changed between compile time and runtime. Using the default implicit insertion of a sentence makes the code more reliable; now that the code has been recompiled, the compiler checks that all cases are handled explicitly. If the developer inserted an explicit default sentence (as today), the possible error would be hidden.

The only thing that is not entirely clear is what the implicit default offer actually does. I assume this will result in an unchecked exception. (Currently, JLS for Java 12 has not been updated to describe new switch expressions.)

+39
Feb 16 '11 at 7:22
source share

As already mentioned, you need to return a value, and the compiler does not assume that the enumeration cannot change in the future. For example. you can create another version of the enumeration and use it without recompiling the method.

Note: for xyz there is a third value that is null.

 public static String testSwitch(XYZ xyz) { if(xyz == null) return "null"; switch(xyz){ case A: return "A"; case B: return "B"; } return xyz.getName(); } 

This is the same result as

 public static String testSwitch(XYZ xyz) { return "" + xyz; } 

The only way to avoid returning is to throw an exception.

 public static String testSwitch(XYZ xyz) { switch(xyz){ case A: return "A"; case B: return "B"; } throw new AssertionError("Unknown XYZ "+xyz); } 
+7
Feb 16 '11 at 7:05
source share

There is a contract under which this method should return String if it does not throw an exception. And every time is not limited to cases when the xyz value is XVZ.A or XYZ.B

Here is another example where it obviuos that the code will work correctly, but where we have a compiletime error for the same reason:

 public boolean getTrue() { if (1 == 1) return true; } 

It is not true that you should add a default statement, it is true that you must return a value at any time. Therefore, either add the default statement, or add a return statement after the switch block.

+1
Feb 16 2018-11-11T00:
source share

In Java 12, you can use the preview switch expression function ( JEP-325 ) as follows:

 public static String testSwitch(XYZ xyz) { return switch (xyz) { case A -> "A"; case B -> "B"; }; } 

and you don’t need the default case if you process all the enum values ​​in switch.

Please note that to use the preview function you need to pass --enable-preview --source 12 options in javac and java

+1
Mar 19 '19 at 13:10
source share

Since the compiler cannot guess that there are only two values ​​in enum , it forces you to return a value from a method. (However, I do not know why he cannot guess, maybe he has something with a reflection).

0
Feb 16 '11 at 6:31
source share
 default: throw new AssertionError(); 
0
Feb 16 '11 at 11:43
source share



All Articles