Branching - Controlling the Flow of a Program (in Java)
Two roads diverged in a yellow wood,
And sorry I could not travel both
…
-Robert Frost, The Road Not Taken
Overview
Concept
The flow of a program can be controlled such that it deviates from its ‘normal’ path.
-
What is a program’s ‘normal’ path?
-
By default, a program will execute statements in the order written, from top to bottom.
-
Some branches are unconditional - the control will always break out of this sequential flow every time the program is executed.
-
Other branches are conditional - certain contextual conditions must be met if the control of the program is to break out of its usual flow.
-
Conditional branches are our focus here.
Flow Charts
Concept
Understanding the flow of a program’s control can be visualized easily with diagrams, irrespective of the programming language and code.
-
Writing code is precarious, laborious, and error-prone.
-
Creating such flow diagrams can help understand and communicate the problem being solved without such burden.
-
The Unified Modeling Language (UML) has attempted to define the “Activity Diagram” - a standard for how such diagrams should be drawn.
-
In practice, people often use parts of the UML Activity Diagram style mixed with their own personal styles.
Example
A virtual card game program randomly picks two cards, from 1 to 11.
- If those two cards add up to 21, the program outputs the text “Blackjack!”
- Otherwise, the program outputs the text, “Maybe next time!”
Example
UML Activity Diagram Rules
UML Activity Diagrams follow a few basic rules:
-
program control starts at the top of the diagram and ends at the bottom.
-
the start point is indicated with just filled circle, the end with a filled circle with a line around it
-
any process is indicated with an ellipse (or a rounded rectangle)
-
if any process being diagrammed is so complex it makes the diagram complex and difficult to understand, make a separate activity diagram for that sub-process, and represent it as a single process in this diagram.
-
any decision point leading to more than one branch is indicated with a diamond shape (also called a rhombus)
-
branches should have simple annotations indicating in what decision context they are followed
If/Else if/Else
Isolated ifs
if statements on their own either execute a particular branch or not.
int card1 = (int) (Math.random() * 11) + 1; // number from 1 to 11
int card2 = (int) (Math.random() * 11) + 1; // number from 1 to 11
if (card1 + card2 == 21) {
// if the cards add up to 21...
System.out.println("Blackjack!");
}
Binary choice
if statements followed by else blocks can have control flow into one of two branches, depending on a single condition being met or not.
int card1 = (int) (Math.random() * 11) + 1; // number from 1 to 11
int card2 = (int) (Math.random() * 11) + 1; // number from 1 to 11
if (card1 + card2 == 21) {
// if the cards add up to 21...
System.out.println("Blackjack!");
}
else {
// otherwise...
System.out.println("Maybe next time!");
}
n-ary
if statements followed by one or more else if blocks can have control flow into one of several different branches, depending on multiple conditions.
int card1 = (int) (Math.random() * 11) + 1; // number from 1 to 11
int card2 = (int) (Math.random() * 11) + 1; // number from 1 to 11
if (card1 + card2 == 21) {
// if the cards add up to 21...
System.out.println("Blackjack!");
}
else if (card1 == 1 && card2 == 1) {
// otherwise if the cards are both ones...
System.out.println("Snake eyes!");
}
else {
// otherwise...
System.out.println("Maybe next time!");
}
UML Activity Diagram
Switch/Case
Concept
In Java, an alternative to if/else if/else statements is switch/case statements.
-
these can be easier to read and write in particular situations.
-
such as when the branch followed depends upon the value of a single variable
-
and when multiple conditions lead to the same branch
Example
Imagine a program that recommends how to dress.
Not using switch / case
This could be handled by if/else if/else statements with some boolean operators thrown in.
Scanner scn = new Scanner(System.in);
String weather = scn.nextLine();
if ( weather.equals("very sunny") || weather.equals("raining") ) {
// if it's raining or very sunny...
System.out.println("Take an umbrella");
}
else if (weather.equals("snowing") ) {
// otherwise, if it's snowing...
System.out.println("Wear a hat!");
}
else {
// otherwise...
System.out.println("Good luck!");
}
Using switch / case
Using switch/case would remove the need for boolean operations and provide more readable code.
Scanner scn = new Scanner(System.in);
String weather = scn.nextLine();
switch (weather) {
case "raining":
case "very sunny":
// if it's raining or very sunny...
System.out.println("Take an umbrella!");
break;
case "snowing":
// otherwise, if it's snowing...
System.out.println("Wear a hat!");
break;
default:
// otherwise...
System.out.println("Good luck!");
}
The Ternary Operator
Concept
It is often the case that we use if/else statements to control setting the value of a variable.
if (breakfastWasServed && breakfastWasEaten) {
satiationLevel = "full"
} else {
satiationLevel = "hungry"
}
The ternary operator, ?
, thankfully allows us to simplify such syntax:
satiationLevel = breakfastWasServed && breakfastWasEaten ? "full" : "hungry"
Conclusions
You now have a basic understanding of UML activity diagrams, if/else if/else statements, and switch/case statements.
- Thank you. Bye.