In a Java program, the statements in the source code are executed sequentially, starting from the first one. The program continues running until all the statements are executed. However, Java also allows looping, decision making and branching in the code. A particular block of statements in the code can be conditionally executed based on decisions. Or a block of statements can be executed multiple times based on a condition. Or the program flow can be branched based on certain conditions. These concepts altogether are called control flow.
There are three types of control flow in Java: decision making, looping and branching.
Decision Making
Decision making is the concept of executing instructions based on some condition being true or not. Java programming language supports decision making is with if blocks. An if block in Java is defined as follows:
if (<condition>) {
<statements to be executed if the condition is true>
}
The condition is a boolean statement that evaluates to true or false. If it is true, the statements inside the if block are executed. Otherwise, program flow moves to the statement following the if block.
We can see how if blocks are used with an example as follows.
int x = 1;
if (x > 0) {
System.out.println(“x is greater than 0”);
y = x + 1;
System.out.println(“The value of x + 1 is “ + y);
}
Here, in this example, the int variable x is initialized with the value of 1. The if condition checks if it is greater than 0. Since this evaluates to true, all the code inside the block is executed. The output would be
x is greater than 0
The value of x + 1 is 2
If the if block contains only one line of code, then using the { and } to mark the beginning and end of the code block is optional. The following two instructions are equal.
if (x > 0) {
System.out.println(“x is greater than 0”);
}
if (x > 0)
System.out.println(“x is greater than 0”);
However, it’s mostly safer to use { and } with if blocks. Failing to use them while the intention was to have a multiline if block causes executing only the first statement that ends with ; conditionally and then executing the following lines unconditionally.
Executing the following lines does not produce an output.
int x = 1;
if (x < 0) {
System.out.println(“x is less than 0”);
System.out.println(“Good job”);
}
However, if we remove the curly braces, the output changes.
int x = 1;
if (x < 0)
System.out.println(“x is less than 0”);
System.out.println(“Good job”);
Here, in this example, the code looks as if the two System.out.println statements are part of the same block. However, there are no curly braces following the if statement. So, only the first line is executed conditionally. Since the condition evaluates to false, the first System.out.println statement does not get executed. The second one gets executed unconditionally. The output becomes
Good job
Java allows additional conditional statements to an if condition to cover different conditions, which is known as if-then-else structure. If we want to cover all the cases other than the one checked with the if statement, we use an else block. If we want to check conditions other than the one checked with the if statement, else if statements and blocks are used. It is possible to use all of them together to check multiple conditions and cover all the remaining conditions with an else block.
If-then-else blocks are defined in Java as follows.
if(<condition1>) {
<statements to be executed if the condition1 is true>
} else if (<condition2>){
<statements to be executed if the condition2 is true>
} else if (<condition3>){
<statements to be executed if the condition3 is true>
}
.
.
.
else {
<statements to be executed if the all the previous conditions are false>
}
In an if-then-else block:
– The first statement has to be an if block. An if-else-then block can’t start with if-else or else.
– else if and else blocks are optional
– There can only be one else block
– There’s no limit on the number of else if blocks
– The same condition can be repeated in the following else if conditions. However, this has no effect on the program flow. The first block with the condition that evaluates to true is executed and the following blocks are skipped. In an if-then-else statement, instructions defined inside only one of the blocks can be executed. Once the execution of the statements inside the block is complete, the program flow moves to the statement following the if-then -else block.
Let’s see all these in an example.
public class MyClass {
public static void main(String [] args) {
int x = 2;
if (x < 1) {
System.out.println(“x is less than 1.”);
} else if (x >= 1 && x < 5) {
System.out.println(“x is is a number between 1 and 5.”);
} else {
System.out.println(“x is greater than 5.”);
}
System.out.println(“Completed the flow.”);
}
Compiling and running this program would give the output
x is a number between 1 and 5
Completed the flow.
The value of x is 2. In the if-else-then block, it is first checked whether x is less than 1. Because this condition is false, the program flow moves into the else if block. The condition for the else if block is true, so the statements inside the else if block are executed. Following this, the else block is skipped and the program flow moves to the last statement inside the main method.
Loops
Loops in a programming language are used to execute the same block of statements multiple times, based on a condition evaluating to true or false. As long as the condition holds true, the instructions inside the loop block are executed. Java defines three types of loops: for, while, do-while
for loops
For loops are defined using the for keyword. The format for defining a for loop is as follows:
for (<initial statement(s)>; <termination condition>; <increment statement(s)>) {
<statements to be executed>
}
– initial statement(s): defines the initial conditions before the looping starts
– termination condition: a condition that evaluates to true or false. Looping happens as long as this condition evaluates to true. If this condition never evaluates to true, the statements inside the block are never executed.
– increment statement(s): defines the update(s) done at the end of each loop. These updates finally lead to the termination condition to evaluate to true. If this never happens, the loop is an endless loop and runs forever.
All 3 of the components inside the for loop definition are optional. If initial condition is undefined, the loop starts running based on the state of the variables at that point in the program. If termination condition is undefined, the loop never ends. If increment statement is not defined, at the end of each loop no increment statement is executed and the code still runs as long as termination condition is false.
The following is a legal for loop declaration which is an endless loop.
for (; ; )
Let’s see for loops in an example.
public static void MyClass {
public static void main(String [] args) {
for (int i = 0; i < 5; i++) {
System.out.println(i);
}
System.out.println(“Finished executing the for loop.”);
}
}
The output would be:
0
1
2
3
4
Finished executing the for loop.
Here, inside the initial condition part of the for loop, the integer variable i is initialized to 1. Now, i is visible to the block but not to the outside the block. Following that, the looping condition is checked. Because i’s value is less than 5, the condition is true and the code inside the block is executed, printing 0 on the console. Next, i’s value is incremented to 1. This is followed by checking the termination condition again, which evaluates to true. So, the code inside the block is again executed, printing i’s current value, 1, to the console. This goes on until termination condition returns false, which happens after i is incremented from 4 to 5. At this point i < 5 returns false and the program flow moves to the first statement following the for block.
Java also allows having multiple initializations and multiple update statements in the for loop. It is important to remember that the initializations should be of the same type and separated by ,. The update statements should be separated by , as well. We can change our for loop to have multiple initialization conditions and multiple increment statements to demonstrate better what happens at each stage.
public static void MyClass {
public static void main(String [] args) {
for (int i = 0, j = 0; i < 5; System.out.println(“Incrementing i and j”),i++) {
System.out.println(i + “ “ + j);
}
System.out.println(“The condition is no longer true. Completed executing the block.”);
}
}
The output would be
0
Incrementing i and j by 1
1
Incrementing i and j by 1
2
Incrementing i and j by 1
3
Incrementing i and j by 1
4
Incrementing i and j by 1
The condition is no longer true. Completed executing the block.
All the statements to the left of the termination condition are executed during initialization and all the conditions to the right of the termination condition are executed following of each loop.
while loops
while loops define only the termination condition and the statements inside a while block are executed as long as the while condition evaluates to true. The format for defining a while loop is
while (<termination condition>) {
<statements to be executed>
}
Because there’s no increment statement, the condition leading to the termination of the while loop needs to develop inside the while loop.
Let’s see while loops in an example.
public class MyClass {
public static void main(String [] args) {
int i = 0;
while (i < 5) {
System.out.println(i);
System.out.println(“Incrementing i to “ + ++i);
}
System.out.println(“The condition is no longer true. Completed executing the block.”);
}
}
The output would be
0
Incrementing i to 1
1
Incrementing i to 2
2
Incrementing i to 3
3
Incrementing i to 4
4
Incrementing i to 5
The condition is no longer true. Completed executing the block.
As you can see, this time we got the same output using a while loop instead of a for loop. The condition that is checked was initialized outside the block and increment was done inside the block, leading to the termination of the block once i’s value was 5.
If the termination condition returns false before the program flow goes into the loop, then the statements inside the loop are never executed.
It is legal to declare endless while loops as follows
while (true) {
…
}
Such loops are used typically while waiting on a thread constantly.
do-while loops
A do-while loop is the same as a while loop except that the loop is guaranteed to execute at least once. The format to define a do-while loop is as follows
do {
<statements to be executed>
} while (<termination condition>);
The statements in the block are executed once and then the first check for termination condition is made. After the first loop, the program flow continues looping as long as the termination condition is true. If, after the first loop the termination condition is false, the code inside the loop never gets executed again. The ; at the end of while statement is required and not having it causes a compiler error.
Let’s see do-while loops in an example.
public class MyClass {
public static void main(String [] args) {
int i = 0;
do {
System.out.println(i);
System.out.println(“Incrementing i to “ + ++i);
} while (i < 5);
System.out.println(“The condition is no longer true. Completed executing the block.”);
}
}
The output would be again
0
Incrementing i to 1
1
Incrementing i to 2
2
Incrementing i to 3
3
Incrementing i to 4
4
Incrementing i to 5
The condition is no longer true. Completed executing the block.
However, if we initialize i to 5 before the loop, we will see that the statements inside the loop are still executed once even though the condition never evaluates to true.
public class MyClass {
public static void main(String [] args) {
int i = 5;
do {
System.out.println(i);
System.out.println(“Incrementing i to “ + ++i);
} while (i < 5);
System.out.println(“The condition is no longer true. Completed executing the block.”);
}
}
The output would be
5
Incrementing i to 6
The condition is no longer true. Completed executing the block.
Branching statements in Java
For a programming language, branching is altering the program flow by transferring the execution from the current branch to a different branch. Java allows moving between branches using three keywords: break, continue and return.
break
break is used to break out of the current execution branch, which in Java corresponds to a loop. The statements inside the loop following the break statement are not executed. Using break keyword out of a loop causes a compilation error. break statement causes the program flow to break out of the current loop. That means, if the execution is inside a nested loop, it only breaks out of the level that it is in.
Let’s see break statements with an example.
public class MyClass {
public static void main(String [] args) {
int i = 0;
while (i < 5) {
System.out.println(i);
if (i > 2) {
System.out.println(“Breaking out of the loop.”);
break;
}
i++;
}
}
}
The output would be
0
1
2
Breaking out of the loop.
Breaking out of a specific loop is also allowed using labels. For that, a label is added in front of a loop and the break keyword is used with the label.
outer:
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (j == 2) {
System.out.println(i + “ “ + j);
break outer;
}
}
}
Here in this example, inside the second loop, when the value of j is 2, the program execution does not break out of the inner loop that it is in, but it breaks out of the outer loop and therefore, practically, exiting the inner loop, too.
continue
continue is used to transfer the execution to the next loop and skip all the statements inside the loop that follow the continue statement. Just like break, continue can be used only inside a for, while or do-while loop. Once continue is executed, the loop keeps running until the termination condition evaluates to true. Just like break, continue applies to the immediate loop that it is in. If it is executed inside a nested loop, only the statements inside the inner loop that follow the continue statement are skipped.
Let’s see continue statements with an example.
public class MyClass {
public static void main(String [] args) {
int i = 0;
while (i < 5) {
if (i == 2) {
System.out.println(“Continuing the loop.”);
continue;
}
System.out.println(i);
}
}
}
0
1
Continuing the loop.
3
4
When i is equal to 2, the continue statement is executed and i’s value is not printed on the console. However, the execution keeps looping over the code until the termination condition is true.
Just like break, continue is allowed to continue the program execution in an outer loop instead of the loop that it is called in, using labels.
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 5; j++) {
if (j == 2) {
System.out.println(i + “ “ + j);
continue outer;
}
}
}
Here in this example, whenever j’s value is 2, the program flow will skip the rest of the inner loop, go back to the outer loop and continue with the new value of i or if i is 5, it will exit the outer loop, too.
return
return statement is used to exit from the current method and return the program flow to the caller method. Void methods cannot return a value but are allowed to use the return value to return the program flow to the caller method. Non-void methods are required to return a variable to their caller method. The type of the returned variable needs to match the one declared in the definition of the method.