5. 0101 - Decisions

Help Make These Materials Better!

I am actively working to complete and revise this eBook and the accompanying videos. Please consider using the following link to provide feedback and notify me of typos, mistakes, and suggestions for either the eBook or videos:

What’s the Point?

  • Understand Boolean expressions

  • Implement if and if-else statements

  • Use else if and nested if-else statements

  • Apply decision structures to object-oriented programming

Source code examples from this chapter and associated videos are available on GitHub.


Decisions, or branching gives our programs the ability to execute different code depending on what’s happening as it runs. At the core of decisions is the concept of Boolean logic, which is named after a 19th-century mathematician named George Boole. Boolean logic is the foundation of the if statements that will be the foundation of our branching code.

5.1. Boolean Expressions

Until now, our programs have all executed very sequentially and predictably—​one line of code after another. How boring! To give our programs the ability to branch and execute different code based on different conditions, we need to introduce the concept of decisions.

In computer programming, a decision is made based on a Boolean expression, which is an expression that evaluates to either true or false. Think of them as questions that can be answered with a simple "yes" or "no". Is this student’s GPA high enough to qualify for the scholarship? Has this cell phone customer used all of their data? Did the user type "exit"?

The true or false value of a Boolean expression can be used to determine which code block will execute next, so it’s important to understand how they work.

Time To Watch!

Boolean Logic in Java

5.1.1. Boolean Values

The simplest way to use Boolean in Java is with the keywords true and false. These can be assigned to variables of type boolean:

1
2
boolean isTimAmazing = true;
boolean isClassBoring = false;

5.1.2. Relational Operations

Also known as comparison operations, relational operations are expressions that compare two values. You will remember them from math class. Is x greater than y? Is a less than or equal to 10? Is c equal to d? Relational operators, like arithmetic operators, are binary operators that require two operands. In other words, we need two values to compare. In our math class, we could draw symbols that aren’t on our keyboard, like a ≥ for "greater than or equal to." In Java, where we have to stick with stuff on our keyboard, we use the following symbols:

Table 3. Java relational operators

Operator

Description

==

Equality (checks if two values are equal)

!=

Inequality (checks if two values are not equal)

<

Less-than

>

Greater-than

<=

Less-than-or-equal-to

>=

Greater-than-or-equal-to

A relational operation will always evaluate to either true or false. We can store that result in a boolean variable, as shown below, and we’ll also learn how to use these expressions in if statements later in this chapter.

1
2
boolean canBuyAlcohol = age >= 21;
boolean isNegative = number < 0;

These assignment statements work like any other: the expression to the right of the equals symbol is evaluated, and the result is stored in the variable on the left.

5.1.3. Testing a String for Equality

In Java, we can’t use the == operator to compare two strings. The following code will not work as we might expect:

Example of an incorrect String comparison.
1
2
3
4
// Should output "true", but (sometimes) doesn't
String name = "Paul McCartney";
System.out.print("Is this person Paul McCartney?");
System.out.println(name == "Paul McCartney");   // DON'T DO THIS!

The == operator does not compare the contents of the strings, but rather the memory addresses where the strings are stored. Due to the nuances of how the Java runtime handles String objects, this code will work sometimes, by coincidence, but it’s not reliable.

Instead, we’ll need to use the equals() method, which is a method of the String class and gets called using dot notation. This method will examine the contents of the strings and return true if they are the same, and false if they are different.

Example of a correct String comparison.
1
2
3
4
// Outputs "true"
String name = "Paul McCartney";
System.out.print("Is this person Paul McCartney? ");
System.out.println(name.equals("Paul McCartney"));
The equals() method is case-sensitive, so "Paul McCartney" is not the same as "paul mccartney". The String class also has a equalsIgnoreCase() method that will compare two strings without regard to case.

5.2. if Statements

The if statement is the most basic decision-making structure in Java. It allows us to execute a block of code only if a certain condition is true.

The syntax of an if statement is the keyword if, followed by a Boolean expression in parentheses, followed by a block of code in curly braces. If the Boolean expression evaluates to true, the block of code will execute. If the Boolean expression evaluates to false, the block of code will be skipped. In either case the program will continue executing the next line of code after the if-block.

Example of an if Statement.
1
2
3
4
5
int age = 20;
if (age < 21) {
    System.out.println("You can't buy alcohol.");
}
System.out.println("Keep that in mind when you go to the store!");

In this example, the if statement checks if the variable age is less than 21. Since 20 is less than 21, the Boolean expression evaluates to true, and the block of code inside the if statement is executed—​and it prints "You can’t buy alcohol." The program then continues to the next line of code, which prints "Keep that in mind when you go to the store!"

If the value of age were 22, the Boolean expression would evaluate to false, and the block of code inside the if statement would be skipped. The program would then continue to the next line of code, which prints "Keep that in mind when you go to the store!"

Keep in mind, the parentheses after the if keyword can contain any Boolean expression—​not just this simple example.

5.3. Adding an else Block

An if statement simply determines whether or not to execute a single block of code. If we want to choose between two blocks of code, we can add an else block to the if statement. The syntax is simple: after the if block, add the keyword else, followed by a block of code in curly braces.

Example of an if-else Statement.
1
2
3
4
5
6
7
8
int age = 20;
if (age < 21) {
    System.out.println("You can't buy alcohol.");
}
else {
    System.out.println("You can buy alcohol.");
}
System.out.println("Keep that in mind when you go to the store!");

An if-else statement will always execute one block of code or the other, but never both. Basically, it’s an either-or situation.

Time To Watch!

if and if-else Statements in Java

File from video:

Interesting!

Java includes a shorthand form of an if-else statement called the ternary operator, which uses the question mark symbol. It’s a useful little trick, but it can be confusing for beginners—​and for the people reading our code later. We won’t look at them in this course, but a web search should turn up plenty of examples if you are curious.

Assignments in my course require you to use full if-else statements, so you shouldn’t use the ternary operator in code you submit to me.

5.4. The if-else if Structure

The if-else structure is great for choosing between two blocks of code, but what if we have more than two options? To handle this, we can chain multiple if-else statements together.

WeatherRecord.java (excerpt). Example of an if-else if statement. See GitHub for the complete file.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public class WeatherRecord {
    // Fields
    private String date;
    private int highTemperature;
    private double averageWindSpeed;

    public String getTempDescription() {
        if (this.highTemperature > 90) {
            return "Hot";
        } else if (this.highTemperature > 70) {
            return "Warm";
        } else if (this.highTemperature > 50) {
            return "Cool";
        } else {
            return "Cold";
        }
    }
}

In this example, the getDescription() method will return a String that describes the weather based on the high temperature of the day.

  • If the high temperature is greater than 90, the method will return "Hot".

  • If the high temperature is greater than 70, the method will return "Warm".

  • If the high temperature is greater than 50, the method will return "Cool".

  • If the high temperature is 50 or less, the method will return "Cold".

The code begins with the first statement, and if it evaluates to true, the corresponding block of code will execute. If the first statement evaluates to false, the program will move on to the next else if statement, and so on. Once a code block is executed, it will hit a return statement, which will exit the method and not evaluate any other blocks of code. Therefore, only one block of code will execute. If the program gets through the entire structure without finding a true condition, it will execute the block of code in the else block, if one is present.

If we’re looking at that code critically, we might notice that the else block is not strictly necessary. We could just put the return "Cold"; statement at the end of the method, and it would work the same way. However, that depends on the logic of the if-else if structure and whether or not we’re using return statements in the blocks of code.

Interesting!

The above example shows one clever use of decisions in an object class. You’d think that a getDescription() method would return the value of a field called description, but there is no field. Instead, it just uses a decision structure to return a description based on the highTemperature field.

In summary, An if-else if structure can execute, at most, one block of code. If an else block is included at the end, it guarantees that exactly one block of code will execute.

Time To Watch!

if-else if Statements in Java

Note: This video also shows how to use if statements in an OOP context, specifically to help with encapsulation.

Files from video:

5.5. Nested if-else Statements

If we want a block of code to execute only if two different conditions are met, we can place if statements inside of each other—​which is called nesting. Nested if statements check multiple conditions in a hierarchical way: if one condition is met, it will proceed and check the next condition; if the first condition is not met, it will skip the inner if block.

Basic structure of a nested if-else statement.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
if (condition1) {
    if (condition2) {
        // executes if both condition1 and condition2 are true
    }
    else {
        // executes if condition1 is true and condition2 is false
    }
}
else {
    // executes if condition1 is false
}

In the example below, the outermost if-else structure checks the high temperature of the day. The if-else structures within those blocks check the average wind speed and return an appropriate description.

WeatherRecord.java (excerpt). Example of a nested if-else statement. See GitHub for the complete file.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public String getFullDescription() {
        if (this.highTemperature > 90) {
            if (this.averageWindSpeed > 10) {
                return "Hot and Windy";
            } else {
                return "Hot";
            }
        } else if (this.highTemperature > 70) {
            if (this.averageWindSpeed > 10) {
                return "Warm and Windy";
            } else {
                return "Warm";
            }
        } else if (this.highTemperature > 50) {
            if (this.averageWindSpeed > 10) {
                return "Cool and Windy";
            } else {
                return "Cool";
            }
        } else {
            if (this.averageWindSpeed > 10) {
                return "Cold and Windy";
            } else {
                return "Cold";
            }
        }
    }
Time To Watch!

Nested if-else Statements in Java

Note: This video also shows how to use if statements in an OOP context, specifically to help with encapsulation.

Files from video:

5.6. Using Logical Operators

In addition to the relational operators, Java also includes logical operators we can use to make more complex Boolean expressions. A logical operator is a binary operation, so it takes two operands—​but the operands are Boolean expressions instead of numbers.

Table 4. Java logical operators

Operator

Name

Description

&&

AND

Evaluates to true if both operands are true

||

OR

Evaluates to true if either operand is true

!

NOT

Evaluates to true if the operand is false; evaluates to false if the operand is true

These operators can be used to combine multiple Boolean expressions into a single, more complex expression. For example, we could check if a student is eligible for a scholarship based on both their GPA (3.5 or better) and their age (younger than 25).

Example of a decision using a logical AND operation.
1
2
3
if (gpa >= 3.5 && age < 25) {
    System.out.println("You qualify for the scholarship!");
}

In this example, the && operator is used to combine two Boolean expressions. The if statement will only execute the block of code if both expressions are true.

Often, the logic we create using an AND operation can be implemented using nested if-else statements, and vice versa.

The OR operation is similar, but only one of the expressions needs to be true for the entire expression to be true.

Example of a decision using a logical OR operation.
1
2
3
4
5
6
boolean isTimAmazing = false;
boolean isClassFun = true;

if (isTimAmazing || isClassFun) {
    System.out.println("You should take this class!");
}

Both operands in an AND or OR operation have to be complete Boolean expressions. Put another way, each side of the && or || operator must be able to evaluate to true or false on its own. The following code is a very common beginner mistake and will not compile:

if (percentage >= 80 && < 90) { …​ }

This reads like "if the percentage is greater than or equal to 80 and less than 90," but the second part of the expression is not a complete Boolean expression. We need to include the variable name and the comparison operator on both sides of the && operator.

The NOT operation is a little different, as it only takes one operand (making it a unary operator_, if you’re nerdy about words, like I am). It simply inverts the value of the operand. If the operand is true, the NOT operation will evaluate to false. If the operand is false, the NOT operation will evaluate to true.

Example of a decision using a logical NOT operation.
1
2
3
4
5
boolean isTimAmazing = false;

if (!isTimAmazing) {
    System.out.println("At least his mom still loves him!");
}

5.6.1. Range Checking

There are a lot of situations where we might need to combine multiple conditions to make a decision, but one of the most common is range checking. Range checking means we want to see if a value is within a certain range.

A common example of range checking is to convert a percentage grade to a letter grade.

Example of range checking using logical operators.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public String getLetterGrade(int percentage) {
    if (percentage >= 90 && percentage <= 100) {
        return "A";
    } else if (percentage >= 80 && percentage < 90) {
        return "B";
    } else if (percentage >= 70 && percentage < 80) {
        return "C";
    } else if (percentage >= 60 && percentage < 70) {
        return "D";
    } else if (percentage >= 0 && percentage < 60) {
        return "F";
    } else {
        return "Invalid percentage";
    }
}

The AND operator && used in this example means that in order to return "B", for example, the percentage must be greater than or equal to 80 and less than 90. If either of those conditions is not met, the program will move on to the next else if statement.

5.7. switch Statements

Java includes a structure called a switch statement that can be used to choose between multiple options. It is essentially another way to write an if-else if structure, but it can be more readable and easier to write in some situations. I generally consider switch structures to be optional—​you can complete all of the assignments in this course without using them—​but they are a useful tool to have in your programming toolbox. And since you see them often in code written by others, it’s good to know how they work.

The basic structure of a switch statement is as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
switch (expression) {
    case value1:
        // Code to be executed if expression equals value1
        break;
    case value2:
        // Code to be executed if expression equals value2
        break;
    case value3:
        // Code to be executed if expression equals value3
        break;
    default:
        // Code to be executed if expression doesn't match any case
}

The expression in the parentheses after the switch keyword is evaluated, and then the program will jump to the case that matches the value of the expression. If there is no match, the program will execute the default block, if it is present.

The break statement is used to exit the switch block due to a behavior of switch that can be confusing to beginners, known as fall-through. If we don’t include a break statement at the end of a case block, the program will continue executing the code in the next case block, even if the value of the expression doesn’t match the case. This can be useful in some situations, but it’s generally not what you want, so you’ll usually see a break statement at the end of each case block.

Example of a switch statement.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public void trafficInstructions(String lightColor) {
    switch (lightColor) {
        case "red":
            System.out.println("Stop!");
            break;
        case "yellow":
            System.out.println("Slow down!");
            break;
        case "green":
            System.out.println("Go!");
            break;
        default:
            System.out.println("Invalid light color.");
    }
}

5.8. Solution Walkthrough

In "solution walkthrough" videos, I give a problem/prompt that is similar to the kinds of work I assign, and then I record myself writing a solution. It’s not absolutely mandatory to watch this video, but students report that these videos are particularly helpful.

Time To Watch!

Decisions - Java Solution Walkthrough

Solution file from video:

Not yet available!


Check Yourself Before You Wreck Yourself (on the assignments)

Can you answer these questions?

  1. Explain what Boolean expressions are and how they are used to make decisions in Java.

  2. Explain the difference between a relational operator and a logical operator.

  3. What is the difference between an if statement and an if-else statement?

  4. How can you write code that runs one code block from multiple options?

Sample answers provided in Stuff That’s Tacked On The End.