A full switch to enum in Java results in a "Missing return statement" error

Suppose we have a switch statement that fully covers all possible cases of the enum parameter and has a zero check, the reason "Missing return statement" will not be compiled.

 enum Foo {ONE,TWO} int fooToInt(Foo foo) { if (foo == null) { throw new NullPointerException(); } switch (foo) { case ONE: return 1; case TWO: return 2; } } 

I know that throwing an exception from the default case either after enumeration, or visiting the enum element instead of switch fix the problem. But I donโ€™t understand the technical reason for this behavior: obviously, there is no possible branch of execution that does not lead to return or throw . It would also be great in some cases to check compilation time to cover all cases.

+5
source share
5 answers

The compiler does not check if you have listed all the constants from Foo as case , and thus raised and failed.

Suppose Foo been defined as:

 enum Foo {ONE,TWO,THREE} 

Then, what will be your method if you pass Foo.THREE as an argument?


As an alternative to the switch approach, you can add an int member to the Foo enumeration and set the corresponding number for each constant:

 enum Foo { ONE(1),TWO(2); int value; Foo(int value) { this.value = value; } } 

This way you wonโ€™t need a switch , and the compiler will ask you to set the appropriate number for any possible new Foo constant.

+5
source

I'm going to take a picture in the dark here without reading any reason for this, but if this is not the main reason for the behavior, this is at least the reason.

Suppose the enumeration instead comes from the library your project depends on. In the version you are compiling, ONE and TWO are the only parameters. However, you can work with a later version (via OSGi or other solutions) that added a different value to THREE . If THREE is passed to fooToInt , it will reach the end of your method and nothing will be returned (or selected). Unfortunately.

This is pretty unpleasant to detect at runtime, so you have to make choices about how this will be handled, even if it really seems impossible at compile time. Some cases, for example, in your example, can be detected and resolved for compilation, while in other cases it could be handled differently (for example, an implicit throw ), but in the list of all things that could be done to improve Java, I would not say that upstairs.

+4
source

Since you did not specify a default, the compiler automatically added it on the next line after the switch block. At this point, the compiler will โ€œnoticeโ€ that there is no return point from the method and gives you this error.

I gave you an example and changed it, but added the following after RutimeException:

 public class Example { enum Foo { ONE, TWO } int fooToInt(Foo foo) { if (foo == null) { throw new NullPointerException(); } switch (foo) { case ONE: return 1; case TWO: return 2; } throw new RuntimeException("Should not have gotten here"); } public static void main(String[] args) { } } 

I compiled the class and used javap -c Example.class to see the actual bytecode (see below). Note the "default: 52" that javac added. This leads to a block section after the switch case, and there I selected a RuntimeException that overwrite the need to return.

 Compiled from "Example.java" public class com.mprv.automation.jenkins.Example { public com.mprv.automation.jenkins.Example(); Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return int fooToInt(com.mprv.automation.jenkins.Example$Foo); Code: 0: aload_1 1: ifnonnull 12 4: new #2 // class java/lang/NullPointerException 7: dup 8: invokespecial #3 // Method java/lang/NullPointerException."<init>":()V 11: athrow 12: getstatic #4 // Field com/mprv/automation/jenkins/Example$1.$SwitchMap$com$mprv$automation$jenkins$Example$Foo:[I 15: aload_1 16: invokevirtual #5 // Method com/mprv/automation/jenkins/Example$Foo.ordinal:()I 19: iaload 20: lookupswitch { // 2 1: 48 2: 50 default: 52 } 48: iconst_1 49: ireturn 50: iconst_2 51: ireturn 52: new #6 // class java/lang/RuntimeException 55: dup 56: ldc #7 // String Should not have gotten here 58: invokespecial #8 // Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V 61: athrow public static void main(java.lang.String[]); Code: 0: return } 
+3
source

The reason is that the compiler didnโ€™t actually go through your switch to check if you have implemented each case, it just checks if the existing cases correspond to the actual values โ€‹โ€‹in Foo - therefore, it needs something, either by default or return .

+1
source

You missed the default block.

Because your method should return some value.

Put return outside the switch statement. Or put the default block

-1
source

All Articles