I have a problem concerning switch/case statements in java in combination with enums.
In my code I want to do something based on the Enum of the type "MatchingMethods" set in the object "currentMethod".
The enum "MatchingMethods" contains several enums in the form
{EXACT_STRING_MATCHING, DEPTH_MATCHING, [...]}
Now the strange thing is though the object "currentMethod" contains an enum of the type "EXACT_STRING_MATCHING" not only the first case is executed but also the second one.
I know there is no break statement after the code of the first case but the code of the second case shouldn't be executed in my opinion because the enum "EXACT_STRING_MATCHING" doesn'T match with "DEPTH_MATCHING".
If I put in a break statement after the first case it seem to be totally fine…
My code is the following:
[...]
MatchingMethods mM = currentMethod.getMatchMethod();
switch (currentMethod.getMatchMethod()) {
case EXACT_STRING_MATCHING:
//do something here
case DEPTH_MATCHING:
comparedNodePair.setDepthMatchResult(currentMetricResult);
break;
[...]
I am totally confused…
May someone be able to help me?
You already mentioned it, you have no break - switch works like goto where the case are labels to be jumped at and no "boundaries" or functions.
This is also the biggest critique concerning switch, because no one would use goto today, but switch which is certainly similar.
But it gets executed, because once one of the case satements is true the flow of execution "falls trough" see here for some information
this is normal if there is no break statement at the end of the case block.
add the break statement is necessary if you only want the exact block to be executed.
Related
Is there an option in the Eclipse workspace properties to change the order that the "incomplete-switch" warning auto-populates cases within the switch statement? For example, if I have an enum:
enum TraversalType{
PREORDER,
INORDER,
POSTORDER;
}
When you use this and have the switch statement warning auto complete the cases within the body of the switch, it seems to always order alphabetically. Is there an option to change this and use the ordering, like in this example, to look like:
switch(TraversalType pType){
case PREORDER:
break;
case INORDER:
break;
case POSTORDER:
break;
}
every time, instead of just after manually entering the cases?
You can't change the ordering of case statements in the Eclipse auto complete feature of "add missing case statements". However you can sort the enum members alphabetically to match the order of the auto inserted switch cases.
This is the code I have:
public enum Modification {
NONE, SET, REMOVE;
}
boolean foo(){
for (S s : sList) {
final Modification modification = s.getModification();
switch (modification) {
case SET:
case REMOVE:
return true;
/*
case NONE:
break;
*/
}
}
return false;
}
And when the code is as seen above, IntelliJ will say:
'for' statement does not loop less... () Reports any instance of for,
while and do statements whose bodies are guaranteed to execute at most
once. Normally, this is an indication of a bug.
Only if I make the following change, IntelliJ will be happy:
for (S s : sList) {
final Modification modification = s.getModification();
switch (modification) {
case SET:
case REMOVE:
return true;
case NONE:
break;
}
}
Why is my for loop not looping if case NONE: is not included in the switch statement?
I just tried this in eclipse and you end up with a compiler warning on the switch statement.
The enum constant NONE needs a corresponding case label in this enum switch on Modification
To resolve the warning I'm given the following options.
Add default case
Add missing case statements
Add #SuppressWarnings 'incomplete-switch' to foo()
If I add the missing case statement then the warning no longer appears. The same as adding the missing case makes your error warning disappear from intellij.
Without the statement for case NONE you can only see two cases, both of which return true. Without knowing the structure of Modification and the extra value of NONE it looks like this loop would just return true on the first iteration of the loop.
Of course the compiler should actually know that there are more values for Modification than SET and REMOVE so the warning is just for good style. Basically your code works but here's how to improve it.
I would choose to add a default statement rather than the missing case. This would be more future proof in case more values are later added to the enum. E.G.
switch (modification)
{
case SET:
case REMOVE:
return true;
default:
break;
}
Personally I'm not a fan of using the fall through on switch statements. What you gain in making the code concise you lose in legibility IMHO. If someone later comes and adds a case between SET and REMOVE it could introduce a bug. Also, having a return statement mid-way through a method can also cause problems. If someone wants to add some code just before the return they may miss all the places. If the method is very simple then multiple returns is fine but you've stated that this is a simplified example and so if this block of code is complicated I would avoid it.
If you're able to use Java 8 then this looks to be the perfect use case for the new stream API. Something like the following should work.
return sList.stream().anyMatch(
modification -> (modification==Modification.SET || modification==Modification.REMOVE)
);
i assume these are your only three cases right?, so basically its saying you are going to hit one of the first two and instantly return true, therefore not looping, just add a default case and everything should work ok, this is good practice also btw.
basically it cant see a case where it doesnt just return instantly without iterating the loop
I'd say its a false positive.
1st indication:
If you run your code through a debugger - and have elements with NONE modification in the list before an element with other modifications - it will actually loop.
2nd indication:
When you look at the generated bytecode, it transforms the switch statement to (sort of - its not exactly the same)
for (S s : sList) {
Modification modification = s.getModification();
switch (modification.ordinal()) {
case 1:
case 2:
return true;
}
}
If you put that in your code, IntelliJ does not complain.
3rd indication:
the warning dissappears if you put an additional statement before the return, i.e. System.out.println();
switch (modification) {
case SET:
case REMOVE:
System.out.println()
return true;
Seems you tricked the inspection with the missing case label and could simply ignore the warning.
I think that IntelliJ's inspections is wrong. I reported it to JetBrains
Edit : it's fixed
Your switch case always breaks or returns. In the first case, you do nothing aka it falls through. The second case returns which causes both the switch and the loop to stop. In the third case you break the switch statement which causes it to stop. It does not however stop the for loop (aka, it keeps iterating).
Either add specific functionality for the SET case or change your behaviour on the REMOVE and NONE cases.
public enum Modification {
NONE, SET, REMOVE;
}
boolean foo(){
for (S s : sList) {
final Modification modification = s.getModification();
switch (modification) {
case SET:
// This case falls through to the REMOVE case
case REMOVE:
return true; // This statement stops the switch, loop and returns true
case NONE:
break; // This statement stops the switch and continues the loop.
}
}
return false;
}
Your switch is not looping without the NONE case because return breaks the loop and returns a value from the function. break breaks the switch loop but continues the for loop.
By request of OP an extra explanation.
Falling through means the next case will be executed until a stop (break or return) is reached. This makes the following code snippets equivelant:
case SET:
case REMOVE:
return true;
is the same as:
case SET:
return true;
case REMOVE:
return true;
The rule squid:128 seems to exist to prevent fall-through in switch case unless explicitly stated. It seems a reasonable rule, as forgetting a break is a common mistake.
However fall-through are perfectly valid when wanted.
The Documentation of this rule states that the only way to achieve a fall-through is to use continue
case 4: // Use of continue statement
continue;
I have also checked the source code of SwitchCaseWithoutBreakCheck are the implementation really check for "continue" statement
#Override
public void visitContinueStatement(ContinueStatementTree tree) {
super.visitContinueStatement(tree);
markSwitchCasesAsCompliant();
}
However, the Java language does not support continue in switch/case. Nor the online documentation nor ./java-checks/src/test/files/checks/SwitchCaseWithoutBreakCheck.java are valid Java programs.
Am I missing something or is this rule fully broken and prevent using fall-through ?
You are totally right in saying that the description here is wrong and then you actually have no way to do not trigger the rule if you want to actually use fallthrough (and thus you might want either to mark issue as false positive in this case or deactivate the rule alltogether)
calling the rule "broken" is an opinion so I won't argue on that ;)
Nevertheless, a ticket has been created to handle the issue : http://jira.sonarsource.com/browse/SONARJAVA-1169
I am attempting to create it so the user will type in a keyword and it will execute that case. This works fine, but I would like the user to also be able to write after the keyword and it will still find the correct case. For example, the user might input "SEARCH dogs and cats" and it would run the "SEARCH" case.
I attempted to do have a temporary variable that stored only the "SEARCH" portion of the string, but I received an error that it had to be a constant in the switch statements. Is there a workaround or will I have to use if else statements?
Here is some test code with the error:
switch(textField.getText)
{
case SEARCH: case textField.getText().split(" ", 2)[0]: // Error is occuring on the second case statement
// Statements
break;
case Default:
lblOutput.setText("ERROR: NOT FOUND");
}
You need to specify one of three things in a case statement:
A constant
An Enum
Default keyword
Refer to
https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.11
In addition, you have a "case" within a "case" with no intermediate "switch" statement.
I am implementing a simple switch case which will switch on an Enum value. Following is the code
ScheduleType scheduleType = ScheduleType.valueOf(scheduleTypeString);
switch (scheduleType) {
case ScheduleType.CRON_EXPRESSION:
System.out.println("Cron");
break;
}
But I am getting the following error in my IDE:
The qualified case label ScheduleType.CRON_EXPRESSION must be replaced with the unqualified enum constant CRON_EXPRESSION
Can somebody explain why do I get this error and what's wrong with the code.
I know the right way to do is to remove the ClassName, but why do I need to do that?
Because generally in comparisons I do use it like for example in equals and all.
Thanks
Leave off the class name. case ScheduleType.CRON_EXPRESSION: should be case CRON_EXPRESSION: instead.
Or in other words, ScheduleType.CRON_EXPRESSION must be replaced with the unqualified enum constant CRON_EXPRESSION.
Mike has explained the how part.
I shall attempt to explain the why part.
The switch case would make sense only if you compare enums of the same type.
Comparing enums of type E1 with that of E2 doesn't make sense.
There was a bug which was raised to request for this feature which touches upon this.