When do I need to initialize a String? - java

Going through some switch command tutorials from various sources. I am trying to create a small program based on this SwitchDemo tutorial ( I have removed some repeated code to save space):
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;
default: monthString = "Invalid month";
break;
}
System.out.println(monthString);
}
}
In this code monthString does not need to be initialized in the line String monthString;. However I want to add user input to the code using Scanner as follows:
import java.util.Scanner;
public class App2 {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int month = scan.nextInt();
String monthString;
switch (month) {
case 1:
monthString = "January";
break;
case 2:
monthString = "February";
break;
case 3:
monthString = "March";
break;
default:
System.out.println("Invalid month");
break;
}
System.out.println(monthString);
}
}
In this case the code does not work and Eclipse tells me I need to initialize monthString; eclipse corrects it by adding = null to String monthString.
What is the reason for this?
P.s I am completely new to Java, so could you explain it like you would to someone who does not know any programming?
Thanks

It's because monthString is a local variable and there's a path you can take where it's not initialized and you're still trying to use it.
That's just not allowed in Java. I think the reason is it's an easy way for Java to prevent you from making a mistake. It forces you to acknowledge that you haven't set monthString to anything yet but you're still trying to use it. 9 times out of 10, that's an mistake on the developers part, so Java won't let you do it.
One way to fix it is to set monthString to something in your default:. You can also initialize it to null, as #Eran said.

You can either initialize it to null when declaring it :
String monthString = null;
or give it some default value in the default clause of the switch.
default:
System.out.println("Invalid month");
monthString = null; // or some other default value
break;
}
If you don't do one of the two, you might reach System.out.println(monthString); before the String is ever initialized, which is an error.

Basically, any time you can get to a statement, any variable used in that statement has to have been initialized.
In your second example, the default case breaks out of the switch statement, but the code then executes the next statement after the switch: System.out.println(monthString). So, the variable has to have been initialized in all code paths that lead there, but it wasn't in the default case.

The reason for this is that it's part of the Java language specification. You are not allowed to access the value of a local variable (or blank final field) if the variable has not been "definitely assigned". The compiler performs an analysis to ensure assignment occurs before an access, no matter what code path is taken to the access.
In the case of your second example, the path through the default switch case never assigns a value to monthString, and then the value of the variable is accessed in the println statement.
The full definite assignment rules are pretty complex. You can read them in chapter 16 of the spec here.

Alternatively you could try something like this:
String monthString;
switch (month) {
case 1:
monthString = "January";
break;
case 2:
monthString = "February";
break;
case 3:
monthString = "March";
break;
default:
monthString = "Invalid month";
break;
}
System.out.println(monthString);
In order to use a local variable in java it must be initialized to something even if that something is setting it equal to null.
What eclipse is doing is following all of the different paths between creating monthString and where it is used in System.out.println(monthString) and determining that there is no place where the monthString is initialized.
If you were to declare monthString within the enclosing SwitchDemo class then your code would also be valid because there is no way for eclipse to determine if another method has set monthString. (You would of course have to declare monthString as static if you were to do this because you can only access static variables from within a static method).

Related

Can you you use conditional statements in other conditional statements?

My question is simple, will the following code work, if it can't is there a way to accomplish the same effect
int day = 5;
String dayString;
switch (if (day > 0) {
case 1:
dayString = "Monday";
day++;
break;
case 2:
dayString = "Tuesday";
day++;
break;
case 3:
dayString = "Wednesday";
day++;
break;
case 4:
dayString = "Thursday";
day++;
break;
case 5:
dayString = "Friday";
day++;
break;
case 6:
dayString = "Saturday";
day++;
break;
case 7:
dayString = "Sunday";
day++;
break;
default:
dayString = "Invalid day";
day++;
break;
}
System.out.println(dayString);
The output should be friday, basically my question is can you put if statements or while or for or do or other statements within the parameters of the respective statements.
Java's syntax has a number of different structures. Of particular relevance here are expressions and statements.
An expression is something that has a value. A statement is an instruction to do something (*).
if is a statement. Its general syntax is:
if (expression) statement
(The {} is a kind of statement too, which is why you can use braces to surround the code you want to execute).
expression has to be of type boolean or Boolean.
switch is also a statement. Its general syntax is:
switch (expression) {
// ...
}
The expression has to be of type int, char, short, byte (or their boxed counterparts), String or enum. You can't use boolean, long, float or double.
Because the switch needs an expression in the parentheses, you can't use a statement there.
(*) Some expressions can "do something" too, that is, they have a side effect, for example i++. These are special expressions in the Java language called StatementExpressions, which can be written as a statement by adding a semicolon: i++; is legal because it meaningfully does something, i; is not.
the above code will not work...there is syntax error in that code.you cannot add an if condition inside the braces of switch ...it expects a variable to evaluate ...the conditions are given using the case statements...to get friday as output simple put the variable 'day' inside the switch braces--like this-> switch(day)

Syntax for switch-case in Java

I'm using switch case in Java for the first time and I'm a bit unsure about the syntax. Assuming the setTeamName function works, which it does, would the following function make all of the teams in my array have the placeholder String as it's name or should I from case 0: since i starts at 0?
public static Team[] makeTeams(){
Team[] teams = new Team[10];
for(int i = 0; i < teams.length; i++){
switch(i){
case 1: teams[0].setTeamName("Arsenal");
case 2: teams[1].setTeamName("Arsenal");
case 3: teams[2].setTeamName("Arsenal");
case 4: teams[3].setTeamName("Arsenal");
case 5: teams[4].setTeamName("Arsenal");
case 6: teams[5].setTeamName("Arsenal");
case 7: teams[6].setTeamName("Arsenal");
case 8: teams[7].setTeamName("Arsenal");
case 9: teams[8].setTeamName("Arsenal");
case 10: teams[9].setTeamName("Arsenal");
}
}
return teams;
}
use break Statement after every instruction in case.
Your case statements would need to start from 0, because as you rightly observe, i starts at zero. However, this appears to be the least of your problems (unless this is just an exercise in using switch case).
You don't need switch case in this situation at all. Plus, you never create any objects in the array, so every time you attempt to access the array at a particular index, you're going to get a null reference exception. The following will suffice:
Team[] teams = new Team[10];
for (int i = 0; i < teams.length; i++) {
teams[i] = new Team();
teams[i].setTeamName("Arsenal");
}
What you've effectively got in your original example is an example of an anti-pattern, the Loop-switch sequence. If you want the original example to work properly using this anti-pattern (for educational purposes only), you need to add break; statements to ensure that your case statements don't fall through:
Team[] teams = new Team[10];
for (int i = 0; i < teams.length; i++) {
teams[i] = new Team();
switch (i) {
case 0: teams[0].setTeamName("Arsenal"); break;
case 1: teams[1].setTeamName("Arsenal"); break;
case 2: teams[2].setTeamName("Arsenal"); break;
case 3: teams[3].setTeamName("Arsenal"); break;
case 4: teams[4].setTeamName("Arsenal"); break;
case 5: teams[5].setTeamName("Arsenal"); break;
case 6: teams[6].setTeamName("Arsenal"); break;
case 7: teams[7].setTeamName("Arsenal"); break;
case 8: teams[8].setTeamName("Arsenal"); break;
case 9: teams[9].setTeamName("Arsenal"); break;
}
}
Without the breaks, every case statement under the one that matches i is evaluated, e.g. when i == 0, all of the case statements will be executed.
You do have options in filling up the array but if your task requires you to use only switch then start with case 0 instead of 1, since 0 is the "first" case you are encountering.
Do you really need switch here? for loop will be enough.
Switch just move execution to case row and ignore another case for next time. So when you give i = 1 to switch all of the case statement will be executed. You can prevent it by using break;
switch (i) {
case 1:
teams[0].setTeamName("Arsenal");
break;
case 2:
teams[1].setTeamName("Arsenal");
break;
}
You are doing a lot of unnecessary work. Try
public static Team[] makeTeams(){
Team[] teams = new Team[10];
for(int i = 0; i < teams.length; i++){
teams[i] = new Team();
teams[i].setTeamName("Arsenal");
}
return teams;
}
You have few errors in your code:
1) You do not have case 0 - so it is not used. Suggestion is always use default case.
2) Each case should be finished with break; Otherwise all cases below are executed too. For example for case 9 these cases are called 9 and 10. and for case 1 all 10 cases have been called. (but for case 0 in your code none is called).
3) You had reserved array of 10 teams but you did not populated objects to this array. You code will produce null pointer exception.

Why do I get a "variable might not have been initialized" compiler error in my switch block?

I'm encountering "a variable might not have been initialized" error when using switch block.
Here is my code:
public static void foo(int month)
{
String monthString;
switch (month)
{
case 1: monthString = "January";
break;
case 2: monthString = "February";
break;
}
System.out.println(monthString);
}
The error:
Switch.java:17: error: variable monthString might not have been initialized
System.out.println (monthString);
To my knowledge this error occurs when you try access a variable you have not initialized, but am I not initializing it when I assign it the value in the switch block?
Similarly, even if the month is a compile-time constant, I still receive the same error:
public static void foo()
{
int month = 2;
String monthString;
switch (month)
{
case 1: monthString = "January";
break;
case 2: monthString = "February";
break;
}
System.out.println(monthString);
}
If month isn't 1 or 2 then there is no statement in the execution path that initializes monthString before it's referenced. The compiler won't assume that the month variable retains its 2 value, even if month is final.
The JLS, Chapter 16, talks about "definite assignment" and the conditions under which a variable may be "definitely assigned" before it's referenced.
Except for the special treatment of the conditional boolean operators &&, ||, and ? : and of boolean-valued constant expressions, the values of expressions are not taken into account in the flow analysis.
The variable monthString is not definitely assigned prior to being referenced.
Initialize it before the switch block.
String monthString = "unrecognized month";
Or initialize it in a default case in the switch statement.
default:
monthString = "unrecognized month";
Or throw an exception
default:
throw new RuntimeExpception("unrecognized month " + month);
This may works fine.
public static void foo(int month)
{
String monthString;
switch (month)
{
case 1: monthString = "January";
break;
case 2: monthString = "February";
break;
default:monthString = "Invalid month";
}
System.out.println(monthString);
}

If-else working, switch not [duplicate]

This question already has answers here:
In a switch statement, why are all the cases being executed?
(8 answers)
Closed 1 year ago.
I am making an app that has a grid of images with text and each one opens a different activity. It works fine but just for design purposes I want to replace my if-else statements with switch statements (which I assume I can do) however it doesn't work. Right now my working code to set the label on each image is:
if(position == 0)
textView.setText(R.string.zero);
else if(position == 1)
textView.setText(R.string.one);
else if(position == 2)
textView.setText(R.string.two);
else if(position == 3)
textView.setText(R.string.three);
else if(position == 4)
textView.setText(R.string.four);
else if(position == 5)
textView.setText(R.string.five);
ect....
I want to use:
switch(position)
case 0:
textView.setText(R.string.zero);
case 1:
textView.setText(R.string.one);
case 2:
textView.setText(R.string.two);
case 3:
textView.setText(R.string.three);
case 4:
textView.setText(R.string.four);
but when I did that ever label was the last one that I defined (in my example it would be "four"). I also have a similar code for each object to start a different intent with the position variable however that does the opposite and makes every intent equal to the first one. Is my syntax wrong or will this not work for my situation?
You need to break; after each statement in a case, otherwise execution flows down (all cases below the one you want will also get called), so you'll always get the last case.
switch(position) {
case 0:
textView.setText(R.string.zero);
break;
case 1:
textView.setText(R.string.one);
break;
case 2:
textView.setText(R.string.two);
break;
case 3:
textView.setText(R.string.three);
break;
case 4:
textView.setText(R.string.four);
break;
}
Here's the official tutorial explaining when to and when not to use break;.
You need to break; after each branch:
switch (position) {
case 0:
textView.setText(R.string.zero);
break; // <-- here
// etc
}
Legitimate uses of switch when you don't break exist, those are called fall throughs; or because you return or throw.:
switch (someNumber) {
case 0:
return 0;
// no need for break here
case 1:
throw new IllegalArgumentException();
// no need to break here
case 2:
System.out.println("Oh, I got two!");
// fall through
case 3:
return 3;
default:
System.out.println("Meh")
// No need to break: last possible branch
}
return -1;
will return 3 even if you enter 2.
But otherwise you need to break.
Using a break statement after each case should fix the problem. I would also use a default statement as well after the last case.
This is the solution. You need to use break to avoid going through each case:
switch(position)
case 0:
textView.setText(R.string.zero);
break;
case 1:
textView.setText(R.string.one);
break;
case 2:
textView.setText(R.string.two);
break;
case 3:
textView.setText(R.string.three);
break;
case 4:
textView.setText(R.string.four);
break;
I would recommend to read the oracle documentation about the switch statement.
You need to use break statement after eace case operations. In a switch-case statement if you dont use a break statement then all the cases after that specific one will be executed also
case 0:
textView.setText(R.string.zero);
break;
Don't forget to put break; after each case: like that:
switch(position){
case 0:
textView.setText(R.string.zero);
break;
case 1:
textView.setText(R.string.one);
break;
case 2:
textView.setText(R.string.two);
break;
case 3:
textView.setText(R.string.three);
break;
case 4:
textView.setText(R.string.four);
break;
}
In the Switch-case statements, you need to put break; after each case.
switch(position){
case 0:
textView.setText(R.string.zero);
break;
case 1:
textView.setText(R.string.one);
break;
case 2:
textView.setText(R.string.two);
break;
case 3:
textView.setText(R.string.three);
break;
case 4:
textView.setText(R.string.four);
break;
default:
System.out.println("not available");
}
Also you need to put default: at last, because when all case are wrong that time perform default: action.
In the switch-case statement not forgot about break; and default action.
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.
Switch is faster than if-else statement
Bottom line : Default is optional(works like else statement in switch), Break is mandatory.
Interesting fact: you won't see any compilation error, even if you forgot to place the break statement.
The switch needs a break with in each case. But in your case it could be done much simpler by defining an array as shown below.
String values = {R.string.zero, R.string.one, R.string.two, ... };
Use this to populate textView : textView.setText(values[position]);

Java: Can I fall through only one case in a switch statement

In Java, can I fall through only one of the cases in a switch statement? I understand that if I break, I will fall through to the end of the switch statement.
Here's what I mean. Given the following code, on case 2, I want to execute case 2 and case 1. On case 3, I want to execute case 3 and case 1, but not case 2.
switch(option) {
case 3: // code
// skip the next case, not break
case 2: // code
case 1: // code
}
No, what you are after is not possible with a switch statement. You will fall through each case until you hit a break. Perhaps you want case 1 to be outside of your switch statement, so that it is executed regardless.
Put the code into methods and call as appropriate. Following your example:
void case1() {
// Whatever case 1 does
}
void case2() {
// Whatever case 2 does
}
void case3() {
// Whatever case 3 does
}
switch(option) {
case 3:
case3();
case1();
break;
case 2:
case2();
case1();
break;
case 1:
case1(); // You didn't specify what to do for case 1, so I assume you want case1()
break;
default:
// Always a good idea to have a default, just in case demons are summoned
}
Of course case3(), case2()... are very poor method names, you should rename to something more meaningful about what the method actually does.
My suggestion is to not use fallthrough for anything except cases like the following:
switch (option) {
case 3:
doSomething();
break;
case 2:
case 1:
doSomeOtherThing();
break;
case 0:
// do nothing
break;
}
That is, giving several cases the exact same block of code to handle them (by "stacking" the case labels), making it more or less obvious what the flow is here. I doubt most programmers intuitively check for case fall through (because the indentation makes a case look like as a proper block) or can efficiently read code that relies on it - I know I don't.
switch(option)
{
case 3:
...
break;
case 2:
...
break;
}
... // code for case 1
You can custom the condition if you want to split cases
const { type, data } = valueNotifications
let convertType = ''
if (data?.type === 'LIVESTREAM' && type === 'NORMAL') {
convertType = 'LIVESTREAM1'
} else convertType = type
switch (convertType)
My use case has split the type from value notifications, but I have a specific LiveStream case which only shows in data.type is 'LIVESTREAM'
Something like this maybe.
switch(option) {
case 3: // code
// skip the next case, not break
// BLOCK-3
case 2: // code
if(option == 3) break;
// BLOCK-2
case 1: // code
// BLOCK-1
}
In switch statement if you don't break the subsequent case is executed. To give you simple example
int value = 2;
switch(value) {
case 1:
System.out.println("one");
break;
case 2:
System.out.println("two");
case 3:
System.out.println("three");
break;
}
Will output
two
three
Because break wansn't executed on case 2

Categories

Resources