tags:

views:

52

answers:

5

I noticed the following in the Java Language spec in the section on enumerations here: link

switch(this) {
  case PLUS:   return x + y;
  case MINUS:  return x - y;
  case TIMES:  return x * y;
  case DIVIDE: return x / y;
}
throw new AssertionError("Unknown op: " + this);

However, looking at the switch statement definition section, I didn't notice this particular syntax (the associated throw statement) anywhere.

Can I use this sort of "default case is throw an exception" syntactic sugar outside of enum definitions? Does it have any special name? Is this considered a good/bad practice for short-cutting this behavior of "anything not in the list throws an exception"?

+1  A: 

I am not sure if I get you, but you seem to believe that the throw is part of the switch syntax in the posted code sample. That is not the case. The switch block and the throw statement are two seperate things, which just happens to be placed next to each other in this code.

In more detail: The four case parts in the switch all contain return statements, causing any subsequent instructions in the method to be skipped. If none of the case parts matches, execution continues on the line following the switch block, which happens to be a throw.

You could use a throw after an if in a very similar way:

if (something) {
    return aValue;
}

throw new Exception("Nope");
Jørn Schou-Rode
Thank you. I completely missed the return statement in each case when I first looked at the code.
Tom Tresansky
A: 

There's a default keyword:

switch (whatever) {
  // ...
  default: explode();
}

If you want the default case to throw an exception, then

  default: throw new Explode();

Your example only works the way it does because all the other branches return from the containing function. In my opinion that's not a very good coding habit to get into.

Pointy
I think explaining that it means you get an exception at run time rather than a 'missing return' compiler error would be better than shouting.
Pete Kirkham
Well I didn't mean to shout at anybody, I was just being emphatic. Often on SO I find myself giving direct answers to questions, and then having to back out and clarify that I think the entire undertaking is a mistake. In this case, I wanted to emphasize that beyond the inherent "code smell" of a `switch` in the first place, that multi-way "return" dispatch is something I'd avoid. It's a matter of opinion of course.
Pointy
A: 

In eclipse, if you do not cover all enum values in a switch statement it generates a warning at compile time.

If, however, you put a default: case that warning does not work anymore. So, yes in some IDEs there is a definite advantage of omitting default case when all enum values are covered in a switch statement.

In general, if your switch statement grows beyond 5-6 cases, consider redesigning the code. Usually, people do not appreciate that enums in Java are full blown classes and enum values are first-class objects, so instead of driving the behavior through the switch statement in many cases you can ask the enum object to do the work itself.

In this particular example the enum can have a method doOp( int x, int y) and each enum member can implement a particular flavor of this method.

Alexander Pogrebnyak
It should be noted that Enum values will only become full blown classes iff the value has a related class body (even if that body is empty {}). Otherwise they will be instances of the Enum class. If you can mimic polymorphism with a switch, and thus avoid declaring the method abstract, you will have fewer classes to load, which may or may not get you anything.
ILMTitan
@ILMTitan: Not true. Even enums with value declarations only are the classes in their own right. They are definitely the descendants of java.lang.Enum, but classes nevertheless.
Alexander Pogrebnyak
@Alexander Pogrebnyak: enum BoolEnum {TRUE(true), FALSE(false){//class-like body}; //contstructors etc.}. BoolEnum will always be its own class. However, because FALSE has a body, its class will be BoolEnum$1, while true's class will just be BoolEnum.
ILMTitan
@ILMTitan: Agree to that. But in your first post you said instances of `Enum` class, and that is not correct.
Alexander Pogrebnyak
A: 

As others have stated, this is not syntax sugar. It works because all of the branches on the switch return from the method. If some other enum value was put into the switch, the switch statement would complete without running any of the branches, after which the throw statement would execute.

switch(this) {
  case PLUS:   return x + y;
  case MINUS:  return x - y;
  case TIMES:  return x * y;
  case DIVIDE: return x / y;
  default: throw new AssertionError("Unknown op: " + this);
}

That code would be functionally equivalent. The major difference between the two is that your switch with no default clause will create a compiler warning if a value is added to the Enum but not to the switch statement.

ILMTitan
A: 

Shame on the writer of that tutorial for throwing an AssertionError - why not make use of the Exceptions that Java provides us already, like UnsupportedOperationException

glowcoder