Java Basics: Control Flow Statements

All about if-then, if-then-else, switch, while, do-while and for statements.

This is the first post in a series covering some of the basics of the Java programming language.  My intention is to add value beyond what’s readily available in the documentation by calling attention to common gotchas and supplying opinions I’ve developed through my own programming experience.  If you’re already a Java programmer, this post is probably not for you.  Unless you like examples about coffee.  This is probably also not a good starting point for someone with zero programming experience.  I’m going to start out by covering control flow statements: if-then, if-then-else, switch, while, do-while and for.  The example code is available on github, but this is also an excellent opportunity to try out JShell.

Posts in the series

  1. Java Basics: Control Flow Statements (this post)
  2. Java Basics: Exception Handling
  3. Java Basics: Custom Exception
  4. Java Basics: Arrays and Collections
  5. Java Basics: Maps
  6. Java Basics: File I/O
  7. Java Basics: NIO Files

Prerequisites

  • Working version of Java
  • Basic understanding of programming concepts

if-then and if-then-else statements

The most basic form of flow control is the if-then statement.   It’s how you say to your program “if this condition is true, do these things.”  In this example, the variable isAwake is set to true, so the if statement will execute and print the output “Good Morning!”  This example uses a simple boolean, but any statement that evaluates to true or false can be used within the parentheses of an if statement including mathematical operations and calls to functions that return type of boolean.

// If statement
boolean isAwake = true;
 
if (isAwake) {
   System.out.println("Good Morning!");
}

The curly braces ({ }) are optional in this example because there is only one statement to execute.  My personal preference based on experience is to always use the curly braces.  I prefer this for two reasons: 1.) it’s slightly easier to read and 2.) it’s easier to deal with when you inevitably need to come back and add more code to your if-then statement.

if (isAwake)
   System.out.println("Good Morning!");

Often you need to execute some code if the condition is true and other code if it’s not.  That’s what the if-then-else statement is for.  In the example below, we’ll see the output of “WAKE UP!”  If we change isAwake to true, we’ll see “Good Morning!”

// If/Else statement
isAwake = false;
 
if (isAwake) {
   System.out.println("Good Morning!");
} else {
   System.out.println("WAKE UP!");
}

Sometimes you need to evaluate for multiple possible situations.  You can add as many else if clauses as you need.  Once Java reaches a true condition in an if-else-then statement, it executes the code and does not evaluate the remaining clauses.  So if more than one clause could evaluate to true, it’s only going to execute the code for the first one.  So in the example below, we only see the message “Just the right level of caffeination.”

// If/then/else statement
int coffeeConsumed = 2;
 
if (coffeeConsumed >= 4) {
   System.out.println("Whoa! Slow down there.");
} else if (coffeeConsumed >= 3) {
   System.out.println("You might think of stopping soon.");
} else if (coffeeConsumed >= 2) {
   System.out.println("Just the right level of caffeination.");
} else if (coffeeConsumed >= 1) {
   System.out.println("You're just getting started.");
} else {
   System.out.println("What no coffee? This is a tragedy!");
}

Gotchas

These examples all deal with primitives.  When comparing objects, including wrapper objects (Integer, Double, etc), you may get unexpected results using the == operator.  Generally, it’s recommended to use .equals() or similar method.  This example using strings demonstrates how comparing with the == can yield unexpected results.  To keep the explanation short and basic, the .equals() method is used by objects to compare their actual content.

String coffeeFlavor = "Columbian";
String coffeeFlavor2 = "Columbian";
String coffeeFlavor3 = "Hazelnut";
String coffeeFlavor4 = new String("Hazelnut");
if (coffeeFlavor == coffeeFlavor2) {
   System.out.println("These coffees are equal");
} else {
   System.out.println("These coffees are NOT equal");
}
 
if (coffeeFlavor3 == coffeeFlavor4) {
   System.out.println("These coffees are equal");
} else {
   System.out.println("These coffees are NOT equal");
}
 
if (coffeeFlavor3.equals(coffeeFlavor4)) {
   System.out.println("These coffees are equal");
} else {
   System.out.println("These coffees are NOT equal");
}

The output contains a possible surprise on the second line by saying coffeeFlavor3 and coffeeFlavor4 are not equal.

These coffees are equal
These coffees are NOT equal
These coffees are equal

Additionally, when comparing strings, you need to consider case.  Unless the values you’re working with are either case sensitive or are totally under your control (a very rare scenario), you can’t be sure what you’re getting.  I would typically write the last part of the previous example like the following example using the equalsIgnoreCase() method.

if (coffeeFlavor3.equalsIgnoreCase(coffeeFlavor4)) {
   System.out.println("These coffees are equal");
} else {
   System.out.println("These coffees are NOT equal");
}

switch statements

A switch statement can be written to function just like an if-then-else statement.  However, a switch statement can also be written to follow multiple paths of execution. Switch can be used on primitives, Strings, Enums and special primitive wrapper classes.  Here’s a switch statement that is functioning like an if-then-else statement with multiple else ifs.  In this example, the code for case 3 is run, printing the output “Wide awake.”  The break; command on the next line tells Java to jump out of the switch statement at that point.  The default label runs if there’s no match on any of the cases.  The switch() takes the variable to be evaluated.  In this example, I used a function Math.abs() to ensure that we weren’t consuming negative cups of coffee…

// Switch Statement using an int
int coffeeConsumed = 3;
String caffeinationLevel = "";
 
switch(Math.abs(coffeeConsumed)) {
   case 5:
      caffeinationLevel = "Totally wired";
      break;
   case 4:
      caffeinationLevel = "Slightly Wired";
      break;
   case 3:
      caffeinationLevel = "Wide awake";
      break;
   case 2:
      caffeinationLevel = "Maintenance level";
      break;
   case 1:
      caffeinationLevel = "Halfway Functional";
      break;
   case 0:
      caffeinationLevel = "Tragically un-coffeed";
      break;
   default:
      caffeinationLevel = "Never Sleeping again!";
      break;
}
 
System.out.println(caffeinationLevel);

An advantage of a switch statement over an if-then-else statement is the ability to evaluate multiple conditions.  This is also a gotcha.  If there’s no break; statement, the program falls through and evaluates the next condition and so on until it either reaches a break; or exits the switch statement.  In this example, the cupsCoffee variable evaluates at case 1 and then falls through incrementing at each case until we end up drinking six cups of coffee.  The output is “Cups of coffee consumed: 6.”

//Switch statement with fall through
int cupsCoffee = 1;
 
switch(Math.abs(cupsCoffee)) {
   case 0:
      cupsCoffee++;
   case 1:
      cupsCoffee++;
   case 2:
      cupsCoffee++;
   case 3:
      cupsCoffee++;
   case 4:
      cupsCoffee++;
   case 5:
      cupsCoffee++;
}
 
System.out.println("Cups of coffee consumed: " + cupsCoffee);

Starting with Java 7, a switch statement can be used with a string.  I’m using the toLowerCase() method to make the switch statement case insensitive.  This is generally a good practice unless the case matters or you’re totally sure of the input.  This example gives the output “Bring your umbrella!” and leaves the switch statement.  This example also demonstrates using multiple case labels for one statement.  The case labels case "sleeting": case "icing":  both print “Go back to bed.”  Which really is the best option if ice is falling from the sky.

//Switch statement with a string
String currentCondition = "raining";
 
switch(currentCondition.toLowerCase()) {
   case "sunny":
      System.out.println("Don't forget your sunscreen!");
      break;
   case "cloudy":
      System.out.println("Hedge your bets: sunscreen and an umbrella!");
      break;
   case "raining":
      System.out.println("Bring your umbrella!");
      break;
   case "snowing":
      System.out.println("Start shoveling");
      break;
   case "sleeting": case "icing": 
      System.out.println("Go back to bed.");
      break;
   case "windy":
      System.out.println("Maybe leave the hat at home today.");
      break;
   default:
      System.out.println("Welcome to New England! We're going to have ALL the weather today.");
      break;
}

It’s very common to see switch statements used with Enums.  An Enum is a special data type for letting one variable hold multiple constants.  They lend themselves very nicely for use in switch statements.  In this example, we have an Enum called Weather for containing weather conditions.

public enum Weather {
   SUNNY, CLOUDY, WINDY, RAINING, SLEETING, SNOWING, ICING
}

This example demonstrates how to use the Enum with a switch statement.  The output is “Go back to bed.”

//Switch statement with an enum
Weather currentWeather = Weather.SLEETING;
 
switch(currentWeather) {
   case SUNNY:
      System.out.println("Don't forget your sunscreen!");
      break;
   case CLOUDY:
      System.out.println("Hedge your bets: sunscreen and an umbrella!");
      break;
   case RAINING:
      System.out.println("Bring your umbrella!");
      break;
   case SNOWING:
      System.out.println("Start shoveling");
      break;
   case SLEETING: case ICING:
      System.out.println("Go back to bed.");
      break;
   case WINDY:
      System.out.println("Maybe leave the hat at home today.");
      break;
   default:
      System.out.println("Welcome to New England! We're going to have ALL the weather today.");
      break; 
}

Gotchas and observations

The easiest way to hurt yourself on a switch statement is by forgetting to use the break; statement when you don’t want to fall through.  The break is optional on the default label, but it’s generally considered a good practice to use one because it’s easier to modify later (if the default becomes another case label for example).  I’ll generally use a switch statement over a really long if-else-then statement if it’s eligible (e.g. an equals comparison, isn’t using objects, etc.) because I think it’s more readable if you get upwards of 4 if thens.

while and do-while statements

The simplest form of loop in Java is the while statement.  The while loop executes as long as the condition is true.  Although the example uses a counter, I typically prefer a for loop for counter driven looping.  A very common application for a while loop is File IO.  Generally, a loop for File IO will keep looping as long as there’s data to read or write to the file.  If the while condition is not true when the execution gets to it, it will not run at all.  If we were to set the counter to 6, nothing will be output.

int counter = 0;
while (counter < 5) {
   System.out.println("Counter = " + counter);
   counter++;
}

This is the output from the example above.

Counter = 0
Counter = 1
Counter = 2
Counter = 3
Counter = 4

The do-while loop works almost exactly like the while loop except that it will always execute once.  So the example below will always print out and increment the counter at least once even if we set doWhileCounter to 6.  I’m not sure I’ve ever used a do-while loop in an actual application.

int doWhileCounter = 0;
do {
   System.out.println("doWhileCounter = " + doWhileCounter);
   doWhileCounter++;
} while (doWhileCounter < 5);

Gotchas

The biggest gotcha with while and do-while loops is infinite loops.  In either of the examples above, if we forgot to increment the counters, we would have an infinite loop.

for statement

The for statement offers a concise way to iterate over a range or collection of values.  The opening line of the following for loop does three things: declares the counter variable i and sets it to 0, sets the condition for looping as i being less than 5 and finally tells Java to increment i by 1 each time through the loop.  The scope of the variable i is only in the for loop.  You could have another for loop below the example that also uses a counter called i.  If you nested a for loop within that for loop, you’d have to use a different variable name for your counter.

for (int i = 0; i < 5; i++) {
   System.out.println("i = " + i);
}

The above loop will give us the following output.

i = 0
i = 1
i = 2
i = 3
i = 4

There is another type of for statement designed for iterating over collections and arrays.  In this form, the for statement declares a variable of the type contained in the collection or array and then after the colon name the collection or array.  So in the example, the string color will contain a value from the colors  array each time through the loop.  I prefer to use this form of the for statement whenever possible, because it’s highly readable.

String[] colors = {"red", "orange", "yellow", "green", "blue", "indigo", "violet"};
for (String color : colors) {
   System.out.print(color + " ");
}

Gotchas

With the for loop, you almost have to be trying to create an infinite loop.  One thing to watch for is if you’re using nested for loops that you are using the correct counter variable in the right loop.  It can get confusing if you’ve got loops in loops and they’ve got counter variables like i, j, k, etc.

break and continue

Sometimes you want to break out of a loop before the condition is met.  That’s where the break command comes in.

for (int i = 0; i < 10; i++) {
   System.out.println("i = " + i);
   if (i == 6) {
      break;
   }
}

The above loop gives us the following output.

i = 1
i = 2
i = 3
i = 4
i = 5
i = 6

Other times, you might want to skip the remaining code in the loop, but keep looping if a certain condition is met.  You can use the continue statement for that.

for (int i = 0; i < 10; i++) {
   System.out.println("i = " + i);
   if (i == 6 || i == 7) {
      continue;
    }
    System.out.println("This is additional code in the loop.");
}

The example above gives us this output.  When i equals 6 and 7, the additional println is not displayed.

i = 0
This is additional code in the loop.
i = 1
This is additional code in the loop.
i = 2
This is additional code in the loop.
i = 3
This is additional code in the loop.
i = 4
This is additional code in the loop.
i = 5
This is additional code in the loop.
i = 6
i = 7
i = 8
This is additional code in the loop.
i = 9
This is additional code in the loop.

Conclusion

This post covered the basics of flow control statements in Java.  I tried to share some of my own experiences, observations and opinions where I thought they’d be helpful.

4 thoughts on “Java Basics: Control Flow Statements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s