I have the following code
public enum Animal {
DOG,CAT;
private void exitWithError(String message){
System.out.println(message);
System.exit(1);
}
@Override
public String toString() {
switch(this){
case DOG:
return "dog";
case CAT:
return "cat";
default:
// missing return statement error
exitWithError("unrecognized animal");
/*
workaround - don't like it
return null;
*/
/* no error if exception thrown
throw new IllegalStateException("unrecognized animal");
*/
}
}
}
The above code results in a missing return statement
error. I have some questions:
The
exitWithError
method should always finish program execution, right?If the method always exits, is there any way I can inform the compiler about it so it doesn't throw the
missing return statement
at me?
The return null
workaround seems to be bad code as if the code changed and this return statement would get executed it could cause problems.
CodePudding user response:
A toString()
method should never exit the program. More generally, almost no methods should attempt to exit the program.
Think about how surprising it would be for System.out.println(EnumSet.allOf(Animal.class));
to cause the program to quit. (It wouldn't, now, but it might if you added another Animal and forgot to update toString()
).
If you want to indicate something is wrong here, throw an exception (or an error), which allows callers to deal with it, if they are able to:
@Override
public String toString() {
switch(this){
case DOG:
return "dog";
case CAT:
return "cat";
}
throw new AssertionError();
}
The throw
is actually unreachable, but the compiler doesn't know this: the throw
is necessary to convince the compiler that the method cannot complete normally (i.e. without returning a value or throwing).
Or, in Java 12 , the compiler will check for the completeness of a switch expression over an enum:
return switch (this) {
DOG -> "dog";
CAT -> "cat";
})
However, an alternative approach (usable pre-Java 12) would be to make the toString()
a parameter of the constructor, so you never have to worry about having an Animal
without a known toString()
:
enum Animal {
DOG("dog"), CAT("cat");
private String string;
Animal(String string) { this.string = string; }
@Override public String toString() { return string; }
}