Weird compilation error when using switch on enumeration - java

I just noticed one curious case and wanted to see if someone will be able to explain it. Here is my case:
private enum Classifiers {
NEURAL_NETWORK, NEAREST_NEIGHBOURS, IDENTITY;
}
private ClassifierInterface getClassifierInstance(Classifiers classifier) {
switch (classifier) {
case NEURAL_NETWORK:
return new DoubleLayeredNeuralNetwork();
case NEAREST_NEIGHBOURS:
return new NearestNeighbours();
case IDENTITY:
return new IdentityClassifier();
}
return null; // If I comment out this line I get compilation error
}
See the comment. I would expect that Unreachable code error will be reported for this line. Instead I get Method must return value error if I comment out this line. However, there is no way the program flow will pass through there.
I even assumed it would be a guard case for the case of null value passed-in, but as expected this triggers NullPointerException for the switch condition.
I do not use switch very often, probably I am missing something here. Can somebody please try to help understand this behaviour?

That is correct behaviour as you do not have a default case statement. The problem is that you could add an value to the enum later and not re-compile the code which uses it. By forcing you to always handle when it is not one of the values, this is covered.
BTW: classifier could be null which is another option switch doesn't handle unfortunately.

That question is interesting...
We have something like this and the compiler is happy!
public enum Coin {
PENNY,
NICKEL,
DIME,
QUARTER;
}
private enum CoinColor { COPPER, NICKEL, SILVER }
private static CoinColor color(Coin c) {
switch(c) {
case PENNY:
return CoinColor.COPPER;
case NICKEL:
return CoinColor.NICKEL;
case DIME: case QUARTER:
return CoinColor.SILVER;
default:
throw new AssertionError("Unknown coin: " + c);
}
}
The Java Languaje Specification says:
A Java compiler is encouraged (but not required) to provide a warning
if a switch on an enum-valued expression lacks a default label and
lacks case labels for one or more of the enum type's constants. (Such
a statement will silently do nothing if the expression evaluates to
one of the missing constants.)

Related

Java enum giving incorrect values [duplicate]

This question already has answers here:
Is custom enum Serializable too?
(3 answers)
Closed 2 years ago.
I have recently started to use Java after a long period of using C,C++ and C#. I can't get my head around how Java enums are supposed to work.
After some research I have created the following:
public class RedRoad implements Serializable, Parcelable
{
// ... other parts removed for clarity
public enum State
{
NOT_STARTED(0),
PART_DONE(1),
COMPLETED(2);
private int value;
private State(int value) {
this.value = value;
}
public void setValue(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
}
I am storing these State values in an sqlite database as ints using getValue(), retrieving them using setValue(), then sending the resulting ''Road' objects via a broadcast. Then I am doing this:
switch (road.state) {
case COMPLETED:
pline.getOutlinePaint().setColor(Color.GREEN); break;
case PART_DONE:
pline.getOutlinePaint().setColor(Color.argb(0xFF,0xFF,0xA5,0x00)); break;
case NOT_STARTED:
default: pline.getOutlinePaint().setColor(Color.RED);
}
but the first two cases are never called, even though I have checked that road.state.getValue() is sometimes 1 , not zero.
Furthermore, if I change the switch code to this:
switch (road.state.getValue()) {
case 2:
pline.getOutlinePaint().setColor(Color.GREEN); break;
case 1:
Log.d("*** road state ", String.valueOf(road.state.getValue()));
Log.e("*** road state ", String.valueOf(road.state));
pline.getOutlinePaint().setColor(Color.argb(0xFF,0xFF,0xA5,0x00));
break;
case 0:
default:
pline.getOutlinePaint().setColor(Color.RED);
}
then the colour gets set as requested. And I get an extraordinary ouput in the log:
D/*** road state: 1
E/*** road state: NOT_STARTED
How can this be? NOT_STARTED is defined as zero!
[Edit]
Later discovered that , apart from the above, (which I can find a workaround for), the values are incorrect after being sent from the async task to the main activity (the 'Road' class is parcelable). If I log state.getValue() before sending , then again after receipt, any non-zero values have changed to zero.
You're calling String.valueOf on an enum constant in the second instance, which calls the toString method of the enum. The default toString implementation of enums returns the name field, which makes NOT_STARTED the valid return value.
Enums are essentially abstract classes with a finite number of implementations, with each implementation guaranteed to only exist once per JVM.
#AndyTurner is correct about not using a setter. I have now done some more tests, in a new app specially created, and the setter gives totally unpredictable results.
So the solution I have used (for setting the value from an 'int' in the db) is a somewhat boring
protected void setState(int i) {
switch (i)
{
case 2: state = State.COMPLETED; break;
case 1: state = State.PART_DONE; break;
default: state = State.NOT_STARTED;
}
}
Although this works , it seems to me to partly defeat the reason for using an Enum (instead of an int) to start with.
And, since creating the setter (that I had originally) gives incorrect results, I wonder why Android Studio (4.1) didn't give me a warning about it? It's very happy to give me warnings about so many other (less important) things.

How to use a switch case in test cases without passing values to switch() method [duplicate]

I've looked at various Q&As on SO similar to this question but haven't found a solution.
What I have is an enum which represents different ways to view a TV Guide...
In the NDroid Application class
static enum guideView {
GUIDE_VIEW_SEVEN_DAY,
GUIDE_VIEW_NOW_SHOWING,
GUIDE_VIEW_ALL_TIMESLOTS
}
...when the user changes the view an event handler receives an int from 0-2 and I'd like to do something like this...
In an Android Activity onClick(DialogInterface dialog, int which) event handler
// 'which' is an int from 0-2
switch (which) {
case NDroid.guideView.GUIDE_VIEW_SEVEN_DAY:
...
break;
}
I'm used to C# enums and select/case statements which would allow something like the above and I know Java does things differently but I just can't make sense of what I need to do.
Am I going to have to resort to if statements? There will likely only ever be 3 choices so I could do it but I wondered how it could be done with switch-case in Java.
EDIT Sorry I didn't completely expand on the issue as I was looking at it as being a generic Java issue. I've added to the question to explain a bit further.
There isn't anything that's Android specific which is why I didn't tag it as Android but the enum is defined in the Application class and the code where I wan't the switch is in an Activity. The enum is static as I need to access it from multiple Activities.
The part you're missing is converting from the integer to the type-safe enum. Java will not do it automatically. There's a couple of ways you can go about this:
Use a list of static final ints rather than a type-safe enum and switch on the int value you receive (this is the pre-Java 5 approach)
Switch on either a specified id value (as described by heneryville) or the ordinal value of the enum values; i.e. guideView.GUIDE_VIEW_SEVEN_DAY.ordinal()
Determine the enum value represented by the int value and then switch on the enum value.
enum GuideView {
SEVEN_DAY,
NOW_SHOWING,
ALL_TIMESLOTS
}
// Working on the assumption that your int value is
// the ordinal value of the items in your enum
public void onClick(DialogInterface dialog, int which) {
// do your own bounds checking
GuideView whichView = GuideView.values()[which];
switch (whichView) {
case SEVEN_DAY:
...
break;
case NOW_SHOWING:
...
break;
}
}
You may find it more helpful / less error prone to write a custom valueOf implementation that takes your integer values as an argument to resolve the appropriate enum value and lets you centralize your bounds checking.
If whichView is an object of the GuideView Enum, following works well. Please note that there is no qualifier for the constant after case.
switch (whichView) {
case SEVEN_DAY:
...
break;
case NOW_SHOWING:
...
break;
}
The enums should not be qualified within the case label like what you have NDroid.guideView.GUIDE_VIEW_SEVEN_DAY, instead you should remove the qualification and use GUIDE_VIEW_SEVEN_DAY
I like a few usages of Java enum:
.name() allows you to fetch the enum name in String.
.ordinal() allow you to get the integer value, 0-based.
You can attach other value parameters with each enum.
and, of course, switch enabled.
enum with value parameters:
enum StateEnum {
UNDEFINED_POLL ( 1 * 1000L, 4 * 1000L),
SUPPORT_POLL ( 1 * 1000L, 5 * 1000L),
FAST_POLL ( 2 * 1000L, 4 * 60 * 1000L),
NO_POLL ( 1 * 1000L, 6 * 1000L);
...
}
switch example:
private void queuePoll(StateEnum se) {
// debug print se.name() if needed
switch (se) {
case UNDEFINED_POLL:
...
break;
case SUPPORT_POLL:
...
break;
This should work in the way that you describe. What error are you getting? If you could pastebin your code that would help.
http://download.oracle.com/javase/tutorial/java/javaOO/enum.html
EDIT: Are you sure you want to define a static enum? That doesn't sound right to me. An enum is much like any other object. If your code compiles and runs but gives incorrect results, this would probably be why.
Short associative function example:
public String getIcon(TipoNotificacao tipo)
{
switch (tipo){
case Comentou : return "fa fa-comments";
case ConviteEnviou : return "icon-envelope";
case ConviteAceitou : return "fa fa-bolt";
default: return "";
}
}
Like #Dhanushka said, omit the qualifier inside "switch" is the key.
enumerations accessing is very simple in switch case
private TYPE currentView;
//declaration of enum
public enum TYPE {
FIRST, SECOND, THIRD
};
//handling in switch case
switch (getCurrentView())
{
case FIRST:
break;
case SECOND:
break;
case THIRD:
break;
}
//getter and setter of the enum
public void setCurrentView(TYPE currentView) {
this.currentView = currentView;
}
public TYPE getCurrentView() {
return currentView;
}
//usage of setting the enum
setCurrentView(TYPE.FIRST);
avoid the accessing of TYPE.FIRST.ordinal() it is not recommended always
I am doing it like
public enum State
{
// Retrieving, // the MediaRetriever is retrieving music //
Stopped, // media player is stopped and not prepared to play
Preparing, // media player is preparing...
Playing, // playback active (media player ready!). (but the media player
// may actually be
// paused in this state if we don't have audio focus. But we
// stay in this state
// so that we know we have to resume playback once we get
// focus back)
Paused; // playback paused (media player ready!)
//public final static State[] vals = State.values();//copy the values(), calling values() clones the array
};
public State getState()
{
return mState;
}
And use in Switch Statement
switch (mService.getState())
{
case Stopped:
case Paused:
playPause.setBackgroundResource(R.drawable.selplay);
break;
case Preparing:
case Playing:
playPause.setBackgroundResource(R.drawable.selpause);
break;
}

Condition coverage on switch statement

When I run coverage on my code below:
private static String mapMyVal(String val) {
switch (val) {
case "foo":
return "FOO_FOO";
case "bar":
return "BARR";
default:
throw new InvalidArgumentException();
}
}
I see "8 out of 10 conditions covered" when I run my unit tests on this with coverage. However I see all three lines being covered inside the statement.
Since there are no other conditions than "foo", "bar" and everything else, what are those missing two conditions?
I see one possible case not covered. The input val might be null. In that case, your switch statement would throw a NullPointerException. To remedy this, you could add null check to the start of the method.
private static String mapMyVal(String val) {
switch (val) {
case "foo":
return "FOO_FOO";
case "bar":
return "BARR";
default:
throw new InvalidArgumentException();
}
}
There was already someone asking nearly the same question. Overall it turned out that going for 100% of unittest for a switch-case might be pure luck because of the way that java is handling the switch-case. See here eclemma branch coverage for switch: 7 of 19 missed

Java forcing default return statement from method with enum switch with all enum values covered

I have the following example situation:
public void shouldReturnStringForEnum() {
MessageType myType = getType();
System.out.println(getMessageForType(myType));
}
String getMessageForType(MessageType myType) {
switch(myType) {
case error:
return "Error type";
case warning:
return "Warning type";
case info:
return "Info type";
}
} // <= error: missing return statement
MessageType getType() {
Random random = new Random();
return MessageType.values()[random.nextInt(3)];
}
enum MessageType {error, warning, info }
I can't figure out what is the possibility to return from method getMessageForType in other way than from the body of switch statement.
I was thinking about:
de-serialization from I/O data - but then java.lang.IllegalArgumentException: No enum constant happen long before call to getMessageForType
possible null method parameter - but then it will fail on switch(myType) evaluation with java.lang.NullPointerException
Forcing a default return statement is uncomfortable in such situations, because I don't know what to return here. Throwing an exception in such case also has no sense here. What is the design decision behind such behaviour?
Please help, what am I missing here?
What happens if you edit the enum later, adding a new constant, without recompiling the switch? That's the case being guarded against.
It's perfectly normal to write default: throw new AssertionError();.
Throwing an exception in such case also has no sense here.
It makes sense because even if you know/think that you will never enter here, you have to handle this case to make your code compliant to the Java compilation rules that expect that the method return a String in any case.
You could spare the exception throw but it would make your code less robust :
String getMessageForType(MessageType myType) {
switch(myType) {
case error:
return "Error type";
case warning:
return "Warning type";
}
return "Info type";
}
Suppose a fine enum value is added and you didn't update getMessageForType() you will return "Info type" instead of.
So this is a fine approach :
String getMessageForType(MessageType myType) {
switch(myType) {
case error:
return "Error type";
case warning:
return "Warning type";
case info:
return "Info type";
}
throw new RuntimeException("Should not happen here ! We get the enum value " + myType);
}
And a better approach would be to add the String associated to each enum as an instance field of the enum :
enum MessageType {
ERROR("Error type"), WARNING("Warning type"), INFO("Info type");
private String msg;
MessageType(String msg){
this.msg = msg;
}
public String getMsg(){
return msg;
}
}
In this way you don't need any longer the switch as well as the getMessageForType() method.
The shouldReturnStringForEnum() method could be as simple as :
#Test
public void shouldReturnStringForEnum() {
System.out.println(getType().getMsg());
}
Java forcing default return statement from method with enum switch with all enum values covered... What is the design decision behind such behaviour?
This is a very important (and correct) decision made by the language. Even though your current code handles all of the current values of the enum, that doesn't mean that the enum class might change long after your code is compiled. You might upgrade a 3rd party library and it might add another enum value causing your code to be invalid at runtime without the default.
Even if you control the enum code that doesn't mean that another developer (or future you) might add another value to the enum and fail to update the switch statement. Writing code that is forward compatible in this manner is generally a best practice and in this case critical for the language to force the behavior.
I don't know what to return here.
The question then comes down to whether to throw an exception or not. How to handle the invalid enum value or other exceptional conditions is something that we as programmers struggle with daily. In this case, you need to ask yourself what you want to happen? Is it an annoyance that shouldn't throw or is it a more critical error? Should the caller handle the exception or is a RuntimeException ok? These are questions you need to answer within the context of your application.
Lastly, I don't know about you, but most programmers I know cut&paste a lot of code. Although this enum may never be expanded, future enums will be expanded and making a good decision may benefit from appropriately handling this case.
Forcing a default return statement is uncomfortable in such situations...
"Unknown type" might be a good choice.
case ...:
return ...;
default:
// here in case someone updates the enum and forgets to update this code
return "Unknown type";
Throwing an exception in such case also has no sense here.
This depends a bit on how big a deal returning the default "unknown" string is. In the case that there is a new enum with a missing case entry, would you want it to throw an exception or not?
For exceptions, you might want to use:
case ...:
return ...;
default:
throw new IllegalStateException("unknown enum type found for" + mType);
or maybe IllegalArgumentException.
You could return a default value out of the switch statement by using the default case of it, like this:
String getMessageForType(MessageType myType) {
switch(myType) {
case error:
return "Error type";
case warning:
return "Warning type";
case info:
return "Info type";
default:
return "unknown message type";
}
} // <= no error anymore
You could alternatively define a default value in a String before the switch statement and return that as default in case of no match in the switch:
String getMessageForType(MessageType myType) {
String r = "unknown message type";
switch(myType) {
case error:
r = "Error type";
case warning:
r = "Warning type";
case info:
r = "Info type";
}
return r;
} // <= no error anymore

Java Switch use variable in multiple cases best practice

I want to have a switch statement like the following:
switch (something)
{
case 1:
int a = 3;
...
break;
case 2:
int a = 4;
....
break;
}
This does not work because a can not be redefined in that scope. I see the following options:
just go with "a = 4" in case 2
put each case in braces
define the variable before the switch statement
use a different variable name in case 2
I don't really like any of those four. Which of those is the way to go, or am i missing the best solution?
I saw questions like this one, which suggest using braces, but they are not about the best way to do it, but about getting it to work at all.
I am guessing you are catching any exception with an illegalstateexception and using a default block.
default:
doSomething();
break;
The oracle style guide does not use braces. It also says that a falls through comment should be added wherever a statement has no break.
However, anything with more than one line can be wrapped in braces with no performance penalty, for readability and reliability. The braces tell the compiler to create a new scope and execute that code as a block. If all you do is change a, then it is not really necessary. If you can write your switch case statement on one line without braces, do it. Many things in java don't do braces in one line instances including if statements.
Next, you can redefine any variable you need to re-use or set in the statements outside of the switch statement. This would be the best practice to minimize continual instantiation of your integers.
If there is more then one line,you should try making a few methods then, go with:
int a=0;
switch (something)
{
case 1:{
a = 3;
...
break;
}
case 2:{
a = 4;
....
break;
}
default:
{
try{
throw new IllegalStateException();
}catch(IllegalStateException e)
{
e.printStackTrace();
}
}
}
The braces is the right way to do it. {} creates a new scope, which is exactly what you want.
You can also use Map:
Map<Integer, Integer> caseMap = new HashMap<Integer, Integer>() {{
put(1, 3);
put(2, 4);
}};
int a = caseMap.get(something);

Categories