Java entries and switch states - the default case?

For people suggesting throwing an exception:
Throwing an exception does not give me a compile-time error, it gives me a runtime error. I know that I can throw an exception, it is better to die at compile time than at runtime.

I am using eclipse 3.4 first.

I have a data model that has a mode property, which is Enum.

enum Mode {on(...), off(...), standby(...); ...} 

I am currently writing a representation of this model and I have code

 ... switch(model.getMode()) { case on: return getOnColor(); case off: return getOffColor(); case standby: return getStandbyColor(); } ... 

I get the error "This method should return a result like java.awt.Color" because I have no default case and no xxx return at the end of the function. I want a compilation error in the case when someone adds another type to the enumeration (for example, shuttingdown), so I do not want to put the default case that generates AssertionError, because it will compile with the changed mode and will not be like an error before execution.

My question is this:
Why does EclipseBuilder (and javac) not recognize that this switch covers all features (or covers them?) And stops warning me about the need to return a type. Is there a way to do what I want without adding methods to the mode?

If this is not the case, is there a warning / error option in the switch statements that do not cover all possible Enum values?

Edit: Rob: This is a compilation error. I just tried to compile it using javac, and I get the "missing return statement" error message aimed at the last method. Eclispe simply puts the error at the beginning of the method.

+49
java enums
May 13 '09 at 18:23
source share
10 answers

You can always use the Enum with Visitor template:

 enum Mode { on { public <E> E accept( ModeVisitor<E> visitor ) { return visitor.visitOn(); } }, off { public <E> E accept( ModeVisitor<E> visitor ) { return visitor.visitOff(); } }, standby { public <E> E accept( ModeVisitor<E> visitor ) { return visitor.visitStandby(); } } public abstract <E> E accept( ModeVisitor<E> visitor ); public interface ModeVisitor<E> { E visitOn(); E visitOff(); E visitStandby(); } } 

Then you implement something like the following:

 public final class ModeColorVisitor implements ModeVisitor<Color> { public Color visitOn() { return getOnColor(); } public Color visitOff() { return getOffColor(); } public Color visitStandby() { return getStandbyColor(); } } 

You would use it as follows:

 return model.getMode().accept( new ModeColorVisitor() ); 

This is much more detail, but you will immediately get a compilation error if a new enumeration is declared.

+65
May 13 '09 at 18:55
source share

You need to enable in the Eclipse settings (window โ†’ settings) "Enum type constant not included in the switch" with the error level.

Throw an exception at the end of the method, but do not use the default case.

 public String method(Foo foo) switch(foo) { case x: return "x"; case y: return "y"; } throw new IllegalArgumentException(); } 

Now, if someone adds a new case later, Eclipse will make him find out that he missed the case. Therefore, never use defaults unless you have a reason to do so.

+56
May 13 '09 at 18:54
source share

I donโ€™t know why you got this error, but here is the suggestion: why donโ€™t you define the color in enum itself? Then you cannot accidentally forget to define a new color.

For example:

 import java.awt.Color; public class Test { enum Mode { on (Color.BLACK), off (Color.RED), standby (Color.GREEN); private final Color color; Mode (Color aColor) { color = aColor; } Color getColor() { return color; } } class Model { private Mode mode; public Mode getMode () { return mode; } } private Model model; public Color getColor() { return model.getMode().getColor(); } } 

btw, for comparison, here is the original case, with a compiler error.

 import java.awt.Color; public class Test { enum Mode {on, off, standby;} class Model { private Mode mode; public Mode getMode () { return mode; } } private Model model; public Color getColor() { switch(model.getMode()) { case on: return Color.BLACK; case off: return Color.RED; case standby: return Color.GREEN; } } } 
+9
May 13 '09 at 18:49
source share

I would say, probably because model.GetMode () could return null.

+6
May 13 '09 at 18:30
source share

Create a default case that throws an exception:

 throw new RuntimeExeption("this code should never be hit unless someone updated the enum") 

... and that pretty much describes why Eclipse complains: as long as your switch can cover all enumeration cases today, someone can add a case and not recompile tomorrow.

+2
May 13 '09 at 18:26
source share

Why does EclipseBuilder not recognize that this switch covers all possibilities (or closes them?) And stops warning me about the need to return a type. Is there a way to do what I want without adding methods to the mode?

This is not a problem in Eclipse, but rather a compiler, javac . All javac sees that you have no return value in the case when nothing is matched (the fact that you know that you match all the cases does not matter). You must return something in the default case (or throw an exception).

Personally, I will just throw some kind of exception.

+2
May 13 '09 at 18:27
source share

Your problem is that you are trying to use the switch statement as an indicator of blocking your enumeration.

The fact is that the switch statement and the java compiler cannot recognize that you do not want to allow other parameters in your enumeration. The fact that you want only three options in the enumeration is completely separate from your design of the switch statement, which, as others point out, should ALWAYS have a default statement. (In your case, this should throw an exception because it is an unhandled script.)

You should freely comment on your enum so that everyone knows not to touch it, and you must correct the switch statement to cause errors for unrecognized cases. Thus, you have covered all the bases.

EDIT

On the issue of compiler error. It doesnโ€™t make much sense. You have an enumeration with three parameters and a switch with three parameters. You want it to throw a compiler error if someone adds a value to the enumeration. Except that the enumerations can be of any size, so it makes no sense to throw a compiler error if someone modifies it. In addition, you determine the size of your enumeration based on the switch statement, which can be located in a completely different class.

The internal workings of Enum and Switch are completely separate and must remain disconnected.

+2
May 13 '09 at 18:48
source share

A good way to do this would be to add a default case to return some error value or throw an exception and use automatic tests using jUnit, for example:

 @Test public void testEnum() { for(Mode m : Mode.values() { m.foobar(); // The switch is separated to a method // If you want to check the return value, do it (or if there an exception in the // default part, that enough) } } 

When you get automated tests, this will take care that foobar is defined for all enumerations.

+2
May 15 '09 at 11:56
source share

Since I canโ€™t just comment ...

  • Always, always, always there is a default case. You will be surprised how โ€œoftenโ€ this will be removed (Less in Java than C, but still).

  • Having said that, if I only want to handle only on / off in my case. Your javac semantic processing will flag this as a problem.

0
May 13 '09 at 18:41
source share

Currently (this answer was written a few years after the original question), eclipse resolves the following configuration in the window โ†’ Settings โ†’ Java โ†’ Compiler โ†’ Error / Warnings โ†’ Potential programming problems:

Incomplete switching cases

Signal, even if the default case is used

0
Dec 28 '16 at 15:50
source share



All Articles