8. Flow control#
This is a straightforward listing of the Java flow control structures.
8.1. Deciding with if
/else if
/else
#
If/else is the basic decision-making mechanism in every programming language. In Java, both “else if” and “else” are optional.
if (condition) {} [else if (condition) {}]* [else {}]?
So, the “if” block is the required basis, “else if” can be used zero to many times - but only directly following the “if”, and the entire statement is closed by an optional “else”.
So these are not legal:
if (foo) { }
else { }
else if (bar) { }
(the else if()
comes after the else
)
if (foo) { }
else { }
else { }
(two else
blocks)
if (foo) { }
int number = 2;
else { }
(the int number = 2;
interrupts the if/else block)
But this is legal:
if (foo) { }
else if {
if (bar) { }
else { }
}
else { }
8.1.1. Single-line blocks#
When there is a single statement in a block (the part between the curly braces) you are allowed to keep it on the same line and omit the braces, as in this example:
boolean foo = getFoo();
if(foo) System.out.println("Foo is true!");
else System.out.println("The foo says no...");
But in such cases you may want to consider using the ternary operator:
boolean foo = getFoo();
String message = (foo ? "Foo is true!" : "The foo says no...")
System.out.println(message);
8.2. Looping with for
#
The “classic” control structure with for
iterates over a collection or a defined series of steps:
for (init; condition; change) { }
“init” is the loop initialization; declaring a counter usually.
“condition” is the test that determines whether the loop should run once more
“change” is the iteration change; usually an increment of the init.
This is a typical for-loop:
String[] nucleotides = {"Adenine", "Cytosine", "Guanine", "Thymine"};
for( int i = 0; i < nucleotides.length; i++) {
System.out.println("nucleotide " + i + " is " + nucleotides[i]);
}
All three elements are optional. This, for instance, is also a legal for-loop:
String[] nucleotides = {"Adenine", "Cytosine", "Guanine", "Thymine"};
int i = nucleotides.length - 1;
for( ; i >= 0; --i) {
System.out.println("nucleotide " + i + " is " + nucleotides[i]);
}
Note that the change does not need to be an increment but can be any change, like the decrement in this example.
Even this one is legal:
for(;;) {
System.out.println("Hello ");
}
//same as
while(true) {
System.out.println("Hello");
}
But it will run into eternity (or until ctrl + c
has been typed). Actually, variations of the second form
are quite often used to wait for user input in a terminal setting:
while(true) {
int answer = getUserInput();
if (answer == 42) break;
}
8.2.1. foreach#
The for-loop also has a variant. It is called the foreach loop. The difference is that there is no increment or condition; it is simply used to iterate a collection (Arrays or Collection types dealt with later).
for (element : collection) { }
And this is a working example:
String[] nucleotides = {"Guanine", "Adenine", "Cytosine", "Thymine"};
for( String nucleotide : nucleotides) {
System.out.println("nucleotide = " + nucleotide);
}
8.3. Looping with while
#
The while
loop is used to loop when there is no predefined number of iterations and/or no underlying collection.
It has two variants:
while (condition) { }
and
do { } while (condition)
The difference is that do{} while()
is guaranteed to execute at least once, whereas while(condition) {}
can be skipped entirely if “condition” is false
at the first evaluation.
8.4. break
and continue
#
All iteration structures (the while
and for
variants) and the switch
structure have the possibility to leave the current iteration early, or the loop entirely.
break
- leave the loop (or theswitch
block)continue
- abort current iteration of the loop and go to next iteration
Here the loop is designed to do nothing with Scorpions.
List<String> zoo = List.of("Giraffe", "Mouse", "Scorpion", "Zebra");
for (String animal : zoo) {
if (animal.equals("Scorpion")) continue;
System.out.println("animal = " + animal);
}
8.5. Discrete options with switch/case
#
The switch/case
structure is a decision flow control structure that is always replaceable by if/else. However, switch/case
is often more efficient, and better suited to deal with choosing between different discrete options.
Where if/else
works with boolean conditions, switch/case
works with discrete cases.
Caution
This structure requires compile time constants to be legal (compilable). These include booleans, Strings, integers and enums, but not float or double or mutable object instances.
The formal description is
switch (actual case) { [case case n: {case specific statement(s)}]* [default: {default statement(s)}]? }
So there are one to many possible case-specific actions and zero or one default actions.
Here is an example method using a switch/case:
void switchCase(String country) {
switch (country) {
case "Netherlands":
System.out.println("Some weather, huh?");
break;
case "Belgium":
System.out.println("Let's get a beer!");
break;
default:
System.out.println("What shall we talk about?");
}
}
and when this is run like this
FlowControlDemo demo = new FlowControlDemo();
demo.switchCase("Netherlands");
we get this output
Some weather, huh?
and when called with an unknown country the default
will be printed.
Note the break
keyword in each case. The break
is a very important aspect of the switch block.
A switch block is fall-through unless a break is encountered.
So if the breaks are removed from the switch
void switchCase(String country) {
switch (country) {
case "Netherlands":
System.out.println("Some weather, huh?");
//break;
case "Belgium":
System.out.println("It is Belgian fries!");
//break;
default:
System.out.println("Have a beer?");
}
}
we get this output
Some weather, huh? It is Belgian fries! Have a beer?
Although this seems rather illogical, there are uses for this behavior. For example, consider this error handler for a web application:
public String errorMessage(int errorCode) {
String message;
switch (errorCode) {
case 401:
case 402:
case 403:
case 405:
message = "You are trying to do something that is not allowed";
break;
case 418:
message = "I am a teapot; I cannot brew coffee";
break;
case 404:
case 503:
message = "Resource not found";
break;
default:
message = "Some exotic error occurred. Try again later";
}
return message;
}
When called like this
void errorMessageTest() {
FlowControlDemo demo = new FlowControlDemo();
String errorMessage = demo.errorMessage(402);
System.out.println(errorMessage);
errorMessage = demo.errorMessage(502);
System.out.println(errorMessage);
}
We get these messages:
You are trying to do something that is not allowed Some exotic error occurred. Try again later