Java 7 - null as case expression [duplicate] - java

This question already has answers here:
How to use null in switch
(14 answers)
Closed 7 years ago.
Why is this failing to compile with an error of "case expressions must be constant expressions"? Isn't null a constant (known at compile time)?
Explicitly casting the null value to String as in case ((String)null) does not help too (I get the same error).
public static String getTypeOfDayWithSwitchStatement(String dayOfWeekArg) {
String typeOfDay;
switch (dayOfWeekArg) {
case null:
typeOfDay = "NULL";
break;
case "Monday":
typeOfDay = "Start of work week";
break;
case "Tuesday":
case "Wednesday":
case "Thursday":
typeOfDay = "Midweek";
break;
case "Friday":
typeOfDay = "End of work week";
break;
case "Saturday":
case "Sunday":
typeOfDay = "Weekend";
break;
default:
throw new IllegalArgumentException("Invalid day of the week: " + dayOfWeekArg);
}
return typeOfDay;
}

Yes, the case expressions must be constant expressions, but null is specifically prohibited by the JLS, Section 14.11, which describes the switch statement:
Given a switch statement, all of the following must be true or a compile-time error occurs:
Every case constant associated with the switch statement must be assignment compatible with the type of the switch statement's Expression (ยง5.2).
If the type of the switch statement's Expression is an enum type, then every case constant associated with the switch statement must be an enum constant of that type.
No two of the case constants associated with the switch statement have the same value.
No case constant associated with the switch statement is null.
At most one default label is associated with the switch statement.
(italics emphasis mine)
As a workaround, you can test for null outside of the switch statement.

The switch statement will throw a NullPointerException if you pass it a null value. Use a separate test to check for null values.

Related

Learning Switch Statements in Java

I'm new to Java and am learning switch statements. However, the wrong case (case "two") seems to be matched. I suspect that it's because of the lack of break; after case "one", but can someone please explain to me the logic behind Java switch statements? Why is case "two" matched at all when the values don't even match?
Here is my code:
String a = "one";
switch(a) {
case "one": System.out.println("a is one");
case "two": System.out.println("a is two");
default: System.out.println("numbers");
}
I expected output:
a is one
numbers
But got:
a is one
a is two
numbers
The case statement is evaluated from top to bottom, when it finds a match it will enter at that point and continue downwards until a break is found (or it gets to the bottom without finding a match). You cannot drop into "one", skip over "two" and re-enter a default.
Default is used when none of the other cases above it match
You need break statements
String a = "one";
switch(a) {
case "one": System.out.println("a is one"); break;
case "two": System.out.println("a is two"); break;
default: //
}
System.out.println("numbers")
Then maybe print the numbers afterward
Each break statement terminates the enclosing switch statement. Control flow continues with the first statement following the switch block. The break statements are necessary because without them, statements in switch blocks fall through: All statements after the matching case label are executed in sequence, regardless of the expression of subsequent case labels, until a break statement is encountered.
If all the cases has been checked and not passed then default case will be executed. Thus in your case the code should be like this.
String a = "one";
switch(a) {
case "one":
System.out.println("a is one");
break;
case "two":
System.out.println("a is two");
break
default:
System.out.println("None of the cases matched ");
}
System.out.println("numbers");
In switch statement, the value of the expression is compared with each of the literal values in the case statements. If a match is found l, the code sequence following the case is executed. However, the default statement is optional.
The break statement is used inside the switch to terminate a statement sequence.
When a break statement is encountered, execution branches to the first of code that follows the entireswitch statement.
This has the effect of jumping out of the switch.
If you omit the break execution will continue on into the next case.

does default case MUST be included in switch statements in Java

I was just wondering if default case MUST be included in switch statements in Java. I understand it is good practice to include default cases. The reason why I ask is because for the code below, if I delete default case, the code will provide error. Could someone please help me clarify the concept? Thanks in advance for any help!
public class SwitchDemo {
public static void main(String[] args) {
int month = 8;
String monthString;
switch (month) {
case 1: monthString = "January";
break;
case 2: monthString = "February";
break;
case 3: monthString = "March";
break;
case 4: monthString = "April";
break;
case 5: monthString = "May";
break;
case 6: monthString = "June";
break;
case 7: monthString = "July";
break;
case 8: monthString = "August";
break;
case 9: monthString = "September";
break;
case 10: monthString = "October";
break;
case 11: monthString = "November";
break;
case 12: monthString = "December";
break;
default: monthString = "Invalid month"; //if delete will produce error
break;
}
System.out.println(monthString);
}
}
While the default clause is not mandatory, if you remove it, monthString may not be initialized, so you get a compilation error when you attempt to print it with System.out.println(monthString);.
You can remove the default clause if you give monthString a default value when you declare it. For example :
String monthString = "Invalid month";
This will give the same behavior as your current switch statement, which includes the default clause.
It is not required to have a default case, but it is a good idea to have one, since this catches cases that you intentionally do not want to handle (or unintentionally didn't handle).
As a point of reference, the Google Java style guide requires a default case.
In your code, assuming you are free of the strictures of a particular style rule requiring a default case, you don't need it; you just need to definitely assign monthString before you can use it (a requirement in the language specification). However, it doesn't make sense to assign a value for a month value outside the range 1-12 - it is logically wrong.
Throwing an exception is a sensible thing to do here, e.g.:
default:
throw new IllegalArgumentException("Invalid month");
If you looks your program you will find your error by own because of Initialization error.
Here
int month = 8;
String monthString; //it is a local Variable and not Initialized.
monthString is not initialized at the time of declaration and this Variable doesn't have global access (not a global Variable) so that it can initialize using any Constructor or any other source.
In your switch statement in all your case you have initialize the variable monthString. If you consider each case and default as a differen branch then you will realize that in all possible branch this code is getting executed. In each possibility variable monthString is initialized but If you Remove this code
default: monthString = "Invalid month"; //if delete will produce error
break;
then there may be a possibility of a default case (if all cases are getting Failed). So, Indirectly you are not consider this default case but there is a possibility of that.
If you still want to remove default case then Initialize your variable monthString at the time of declaration. It will also remove your Compile time error.
This is the reason of getting error after removing the default keyword.
Thank you

Combining assert and switch statements

I was answering a Java test and come across the question:
Which of the following statements is true?
A. In an assert statement, the expression after the colon ( : ) can
be any Java expression.
B. If a switch block has no default, adding an assert default is considered appropriate.
C. In an assert statement, if the expression after the colon ( : ) does not have a
value, the assert's error message will be empty.
D. It is appropriate to handle assertion failures using a catch clause.
The right answer is B. To be honest, I answered that question by excluding another obviously wrong cases, but I can't get the point of that question actually. Could anyone explain why it is true? Where can it be helpful?
I guess it means you should protect yourself from missing a switch case.
Say you have an enum Color {red, green} and this switch in the code:
switch(color) {
case red:
doSomethingRed();
break;
case green:
doSomethingGreen();
break;
}
If in the future you add a new color blue, you can forget to add a case for it in the switch.
Adding failing assert to the default case will throw AssertionError and you will discover your mistake .
switch(color) {
case red:
doSomethingRed();
break;
case green:
doSomethingGreen();
break;
default:
assert false : "Oops! Unknown color"
}
This depends on the case but the way I see it
// Consider expecting only 1,2 or 3 as switch case
switch(x)
{
case 1:
// operations
break;
case 2:
// operations
break;
case 3:
// operations
break;
default: assert false : "Input should be between 1-3";
}
Might be convenient as any other input you might receive can be perceived as a faulty input.
Using assert false in switch block's default is applicable in the public method context e.g.
public void methA(int x) throws Exception {
if(x!=1 && x!=2 && x!=3)
throw new IllegalArgumentException("from Exception: x should be between 1,2 and 3");
switch(x)
{
case 1: doSomething(); break;
case 2: doSomething(); break;
case 3: doSomething(); break;
default: assert false : "from default: x should be between 1,2 and 3";
}
}
If the switch block is used in a public method, then checking the value of the argument x is already handled by an exception before the switch statement.
So, even when you use the assert false in default, that code is never reachable, since the assumption that x is 1,2 or 3 is always true. If not true, it is already handled by the IllegalArgumentException before the switch default. So basically, the assumption that switch-default will never be reached is always true. Hence it is appropriate in the context of public method.

why commenting the throw new IllegalArgumentException in code below gives error for line "return typeofDay" as "variable not initialized"

public String getTypeOfDayWithSwitchStatement(int dayOfWeekArg) {
String typeOfDay;
switch (dayOfWeekArg) {
case "Monday":
typeOfDay = "Start of work week";
break;
case "Tuesday":
case "Wednesday":
case "Thursday":
typeOfDay = "Midweek";
break;
case "Friday":
typeOfDay = "End of work week";
break;
case "Saturday":
case "Sunday":
typeOfDay = "Weekend";
break;
default:
throw new IllegalArgumentException("Invalid day of the week: " + dayOfWeekArg);
}
return typeOfDay;
}
Commenting the following line, throws compilation error:
throw new IllegalArgumentException("Invalid day of the week: " + dayOfWeekArg);
Also typeOfDay is treated as uninitialized variable.
But why it is not treated as uninitialized variable before.
Suppose that dayOfWeekArg contains something else than the name of a day, so in the switch statement the default case is reached.
If you do not throw the exception there, execution will continue to the return statement at the bottom of the method, but typeOfDay will not have been set to any value. That's an error.
If you do throw the exception, the return statement can never be reached when dayOfWeekArg contains anything else than the name of a day, so there is no problem.
Because if your code flow goes through the default section, and
there's no exception thrown there your variable typeOfDay will
indeed be uninitialized. While when there's an exception thrown,
the compiler knows that you cannot pass through the default
section and continue downwards after it (as the exception will be thrown).
Read through your switch statement:
The variable will be assigned a value if it equals to one of the cases, right? But what happens if it does not equal one of the statements? Then it should go through the default case.
If you have the default case with a throw new... then nothing is going to be returned to the user and it doesn't matter whether the variable is initialized or not. Now when you comment the throw new... the compiler realizes that there is a possibility of returning the variable typeOfDay without a value, since it didn't go through any of the case statement and the default one doesn't do anything to it.
It is trying to save you a headache by warning you of a possibility of returning the variable without a value. This can be solved by initializing your variable.

Why does this Java Switch-Case not work?

So, all variables in the conditions are static strings. type itself is a string in fact.
switch(type) {
case (INT || TINYINT):
preparedStatement = setInteger(preparedStatement, value, index);
break;
case (BIGINT || LONG):
preparedStatement = setLong(preparedStatement, value, index);
break;
case (DATETIME || TIMESTAMP):
preparedStatement = setTimestamp(preparedStatement, value, index);
break;
case (MEDIUMTEXT || ENUM || TEXT || LONGTEXT || VARCHAR):
preparedStatement = setString(preparedStatement, value, index);
break;
}
First, switch statements on strings are supported in Java 7+, but not in Java 6 and before.
Next, the || operator (the logical-OR operator) only works on boolean values, not String values. But you can get the same code to be run on multiple cases by listing the cases and not breaking until past the relevant code:
switch(type) {
case INT:
case TINYINT:
// This code will run for INT and TINYINT only.
preparedStatement = setInteger(preparedStatement, value, index);
break;
case BIGINT:
case LONG:
// This code will run for BIGINT and LONG only.
preparedStatement = setLong(preparedStatement, value, index);
break;
// etc.
Java 7 example:
public String getTypeOfDayWithSwitchStatement(String dayOfWeekArg) {
String typeOfDay;
switch (dayOfWeekArg) {
case "Monday":
typeOfDay = "Start of work week";
break;
case "Tuesday":
case "Wednesday":
case "Thursday":
typeOfDay = "Midweek";
break;
case "Friday":
typeOfDay = "End of work week";
break;
case "Saturday":
case "Sunday":
typeOfDay = "Weekend";
break;
default:
throw new IllegalArgumentException("Invalid day of the week: " + dayOfWeekArg);
}
return typeOfDay;
}
Further I have never seen an OR statement inside of a switch like that. I would highly recommend not doing that.
Assuming you are using Java SE 7 (or later) and the constants are static final Strings, then the syntax is not Java.
case INT: case TINYINT:
What does this expression evaluate to?
INT || TINYINT
What are the datatypes for INT and TINYINT
I've only ever seen switch used with some primitives (and new in Java 7, string) literals or variables declared as final.
If this isn't throwing a compile error, then the || operator must be defined for whatever datatype those are. But unless that's somehow being resolved at compile time, that operator is not going to be allowed. (Again, this might be something new in Java 7 I'm not aware of.)
If you are trying to do "or" logic, the normative pattern (in pre-7 versions of Java at least), is:
switch(type) {
case INT:
case TINYINT:
preparedStatement = setInteger(preparedStatement, value, index);
break;
case BIGINT:
case LONG:
preparedStatement =
break;
It is supported on and after java 7
You cannot use logical operators in switch statements, even with Strings. You can only test one case at a time.

Categories