Logical AND, OR, and NOT

The AND, OR, and NOT operators take one or more booleans as input and produce a boolean as output. If you’ve ever studied logic gates such as in electronics, it’s the same principle.

Logical AND

The AND operator is && (double-ampersand). The AND operator takes two booleans as input and produces a single boolean as output. It only outputs true if both inputs are true. In any other case, it outputs false. The two input booleans go either side of the operator, like this:

true && false

This particular operation would result in false because the right boolean is false, and the AND operator only produces true when both are true. Table 1 shows all the possible combinations, where A and B are inputs and A && B is the output.

ABA && B
truetruetrue
truefalsefalse
falsetruefalse
falsefalsefalse
Logical AND (&&)

As we can see, when A and B are true individually, then A && B is also true. If either one is false, then A && B is false. A real-world example of this is taking a flight on a plane. If A is your passport and B is your ticket, then you need both in order to board the plane. If you don’t have one or the other, or neither, then you cannot board the plane.

Here is a simplified version of the roller coaster program using the AND operator:

public static void main(String[] args) {
   Scanner sc = new Scanner(System.in);

   System.out.println("Welcome to SuperFast Roller Coaster!");
   System.out.print("Please enter your height in centimetres: ");
   int height = sc.nextInt();

   if (height > 130 && height < 210) {
       System.out.println("Your height is acceptable. Go ahead.");
   }
   else {
       System.out.println("Sorry, you do not meet the height requirements.");
   }
}

On line 8, the if block uses && to ensure that the person is both tall enough and short enough. It checks that both height is greater than 130 AND height is less than 210. If both expressions are true, the if block runs. If either are false, the else block runs. To solidify this, here are a few runs:

[Run 1]
Welcome to SuperFast Roller Coaster!
Please enter your height in centimetres: 225
Sorry, you do not meet the height requirements.

In Run 1, 225 is entered so height = 225. Therefore, the condition works as follows:

(225 > 130 && 225 < 210)
(true && false)
(false)

It’s false, therefore the else block runs.


[Run 2]
Welcome to SuperFast Roller Coaster!
Please enter your height in centimetres: 136
Your height is acceptable. Go ahead.

In Run 2, 136 is entered. This results in:

(136 > 130 && 136 < 210)
(true && true)
(false)

It’s true, therefore the if block runs.


[Run 3]
Welcome to SuperFast Roller Coaster!
Please enter your height in centimetres: 117
Sorry, you do not meet the height requirements.

In Run 3, 117 is entered. This results in:

(117 > 130 && 117 < 210)
(false && true)
(false)

It’s false, therefore the else block runs.

Logical OR

The logical OR operator is || (double-pipe). A || B outputs true if either A or B is true, otherwise A || B outputs false. This is shown in Table 2.

ABA || B
truetruetrue
truefalsetrue
falsetruetrue
falsefalsefalse
Logical OR (||)

Looking back at the program, we can see that the if block represents the positive response and the else block represents the negative response. What if we flip them around? In that case, we would have to modify the condition and use the OR operator:

public static void main(String[] args) {
   Scanner sc = new Scanner(System.in);

   System.out.println("Welcome to SuperFast Roller Coaster!");
   System.out.print("Please enter your height in centimetres: ");
   int height = sc.nextInt();

   if (height < 130 || height > 210) {
       System.out.println("Sorry, you do not meet the height requirements.");
   }
   else {
       System.out.println("Your height is acceptable. Go ahead.");
   }
}

The program produces the same result, it’s just a different way of writing it. On line 8, this time the condition checks if height is less than 130 OR height is greater than 210. If either are true, then the customer is either too short or too tall (we don’t know which), therefore the if block runs and they are told they cannot go on the ride. Both need to be false for the else block to run. Here are a couple run-throughs:

[Run 1]
Welcome to SuperFast Roller Coaster!
Please enter your height in centimetres: 113
Sorry, you do not meet the height requirements.

In Run 1, the customer enters 113. This results in:

(113 < 130 || 113 > 210)
= (true || false)
= (true)

A result of true means the if block runs. This makes sense as the customer does not meet the requirements (too short).


[Run 2]
Welcome to SuperFast Roller Coaster!
Please enter your height in centimetres: 205
Your height is acceptable. Go ahead.

In Run 2, the customer enters 205. This results in:

(205 < 130 || 205 > 210)
= (false || false)
= (false)

A result of false means the else block runs. This makes sense as the customer’s height is within the limits.

To summarise, the first program uses the && to specifically check that the person’s height is inside the range of 130 and 210, whereas the second program uses the || to specifically check that the person’s height is outside the range of 130 and 210. Due to the laws of logic, this means the responses end up swapping blocks.

Combining AND and OR

We can combine as many expressions as we like using the AND and OR operators. For example, let’s now say that anybody whose name is Frank can go on the ride regardless of their height. We will ask for the customer’s name and store it in a variable called name as a String. But how do we compare strings? How do we check that name is equal to “Frank”? Your first thought may be to use the “equal to” operator, like this:

name == “Frank”

But you shouldn’t do it this way because the == doesn’t compare strings in the way you’d expect. Instead, for checking String equality, you should use the method equals like this:

name.equals(“Frank”)

This will compare the string in name with the string “Frank”. If they are the same, it will return true. If they are different, it will return false. The equals method is a member of the String class so all strings you create can use the equals method for checking equality with another string. This method is demonstrated below.

public static void main(String[] args) {
   Scanner sc = new Scanner(System.in);

   System.out.println("Welcome to SuperFast Roller Coaster!");
   System.out.print("Please enter your height in centimetres: ");
   int height = sc.nextInt();
   System.out.print("Please enter your first name: ");
   String name = sc.next();

   if (height > 130 && height < 210 || name.equals("Frank")) {
       System.out.println("Credentials accepted. Go ahead.");
   }
   else {
       System.out.println("Sorry, you do not meet the requirements.");
   }
}

Lines 7 and 8 have been added to obtain the user’s name, which is stored in variable name. On line 10, the code name.equals("Frank") has been appended using the || operator. You can basically read the condition in English: IF the customer is taller than 130cm AND shorter than 210cm OR their name is Frank, THEN they can go on the ride. ELSE they cannot.” Sometimes these kinds of conditions are confusing so it can be beneficial to work out each expression individually. Take the following example:

[Run 1]
Welcome to SuperFast Roller Coaster!
Please enter your height in centimetres: 121
Please enter your first name: Sally
Sorry, you do not meet the requirements.

In Run 1, 121 has been entered for the height and “Sally” for the name, therefore the condition can be broken down like so:

121 > 130 && 121 < 210 || "Sally".equals("Frank")
= false && true || false
= false || false
= false

Therefore, the else block runs.


[Run 2]
Welcome to SuperFast Roller Coaster!
Please enter your height in centimetres: 114
Please enter your first name: Frank
Credentials accepted. Go ahead.

In Run 2, 114 has been entered for the height and “Frank” for the name. Here’s how Java evaluated it:

114 > 130 && 114 < 210 || "Frank".equals("Frank")
= false && true || true
= false || true
= true

Therefore, the if block runs.


It’s a good idea to use brackets to define the order of operations, so it’s clear what happens when. Let’s see what happens if we surround the second and third expressions with brackets:

if (height > 130 && (height < 210 || name.equals("Frank"))) {

and then enter exactly the same information as Run 2:

[Run 3]
Welcome to SuperFast Roller Coaster!
Please enter your height in centimetres: 114
Please enter your first name: Frank
Sorry, you do not meet the requirements.

Even though Run 3 is the same as Run 2, the result is different because of the brackets. This causes the else block to run instead of the if block. Here’s how Java evaluated it:

114 > 130 && (114 < 210 || "Frank".equals("Frank"))
= false && (true || true)
= false && true
= false

Without any brackets the program does do the correct thing by evaluating the && before the ||, but we can still surround the && operation with brackets for the sake of clarity:

if ((height > 130 && height < 210) || name.equals("Frank")) {

Logical NOT

Finally, there’s the NOT operator, which is a single exclamation mark ( ! ). The ! goes before a boolean and simply inverts it, so !true is false and !false is true. In other words, “not true” is “false” and “not false” is “true”. To demonstrate the NOT operator, let’s now say that anyone named Frank cannot go on the ride. The condition could be written with two && operators like this:

if ((height > 130 && height < 210) && !name.equals("Frank")) {

Now, you can only go on the ride if your height > 130 AND height < 210 AND your name is NOT Frank. Run 1 shows us what happens when height = 150 and name = Frank.

[Run]
Welcome to SuperFast Roller Coaster!
Please enter your height in centimetres: 150
Please enter your first name: Frank
Sorry, you do not meet the requirements.

Breaking it down:

(150 > 130 && 150 < 210) && !"Frank".equals("Frank")
= (true && true) || !true
= true && false
= false

Even though the height is fine and results in true, the ! turns the true into a false. Here it is in a clearer form:

Nested if Statements

You can put if statements inside if statements. This gives you more fine-grained control than stuffing multiple conditions into one. Taking the previous example (again), imagine there is now a height restriction and an age restriction. You must be between 130cm and 210cm tall and you must be at least 7 but under 80 years old. For this, you could write a one-liner condition:

height > 130 && height < 210 && age >= 7 && age < 80

This can be read as “If height is greater than 130 AND height is less than 210 AND age is greater than or equal to 7 AND age is less than 80.” But this means you have to enter both your height and age before you are told whether your features are acceptable. Using nesting, we can ask for the height, check it, and only if it’s valid, ask for the age.

import java.util.Scanner;

public class NestedIfStatements {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        System.out.println("Welcome to SuperFast Roller Coaster!");
        System.out.print("Please enter your height in centimetres: ");
        int height = sc.nextInt();
        
        if (height > 130 && height < 210) {
            System.out.println("Height accepted.");
            System.out.print("Please enter your age: ");
            int age = sc.nextInt();
            
            if (age >= 7 && age < 80) {
                System.out.println("Age accepted. Go ahead.");
            }
            else {
                System.out.println("Sorry, you do not meet the age requirements.");
            }
        }
        else {
            System.out.println("Sorry, you do not meet the height requirements.");
        }
    }
}

Like before, the program obtains the height on lines 8 and 9. Then line 11 checks if height is between 130 and 210. If this is false, the else block (lines 23-25) informs the user their height is unacceptable and the program ends after that. On the other hand, if true, line 12 informs the user their height is accepted. Lines 13-14 then obtain the user’s age, stored in variable age. Lines 16-21 is another if statement that checks if age is a valid value (greater than or equal to 7 AND less than 80). If true, line 17 informs the user their age is acceptable. If false, line 20 informs the opposite. Let’s go through the three possible outcomes.

[Run 1]
Welcome to SuperFast Roller Coaster!
Please enter your height in centimetres: 123
Sorry, you do not meet the height requirements.

In Run 1, a height of 123 is too short. This means the condition on line 11 is false, meaning just the else block on line 23 runs.


[Run 2]
Welcome to SuperFast Roller Coaster!
Please enter your height in centimetres: 142
Height accepted.
Please enter your age: 6
Sorry, you do not meet the age requirements.

In Run 2, a height of 142 is between 130 and 210, meaning the condition on line 11 is true. Therefore, the program goes into the if block. The program obtains the age (line 13-14) and checks it on line 16. An age of 6 is too young causing the condition to be false. This means the else block (line 19) runs and line 20 tells the customer they are not of a suitable age. You may wonder where the program goes from here. Remember that once a block completes, the program skips to the end of the if statement. However, there’s no more code after this inner if statement, it’s simply the end bracket of the enclosing if block (line 22). Therefore, the program skips to the end of this outer if statement. There’s no code after this except the closing bracket of the main method (line 26) so the program simply ends.


[Run 3]
Welcome to SuperFast Roller Coaster!
Please enter your height in centimetres: 175
Height accepted.
Please enter your age: 52
Age accepted. Go ahead.

In Run 3, 175 is entered, which is an acceptable height so line 11 evaluates to true and the if block executes. Then, 52 is entered, which is an acceptable age so line 16 evaluates to true and the if block executes and customer is told they can go ahead. This inner if statement finishes. In turn, the outer if statement finishes. In turn, then the main method finishes, ending the program.

Variable Scope

Variable scope relates to the context in which variables can be used. if statements present the first instance where scope becomes an issue. In short, variables can only be used within the block in which they are declared. Take the following example:

public class Scope {
    public static void main(String[] args) {
        int x = 5;

        if (true) {
            x = 10;
            System.out.println(x);
        }

        x = 15;
        System.out.println(x);
    }
}
[Run]
10
15

On line 3 variable x is declared and set to 5. Lines 5-8 is an if statement that sets x to 10 and then prints x. After, line 10 sets x to 15 and lines 11 prints x. How x is being used here is not important. What is important is where is it being used. Since x is declared (on line 3) at the highest level (that is, not in any sub-blocks) it has the widest scope, meaning it can be used anywhere inside the method. This means x can be used on lines 10 and 11, which are at the same level as its declaration (line 3). This also means x can be used at a deeper level, inside the if statement, on lines 6 and 7. But, what happens if we declare x inside the if statement instead?

public class Scope {
    public static void main(String[] args) {
        if (true) {
            int x = 5;
            x = 10;
            System.out.println(x);
        }

        x = 15;
        System.out.println(x);
    }
}

Line 4 is the declaration of x, and because it’s declared inside the if block, it can only be used inside that block. This means lines 9 and 10 will produce errors because they are outside the if block and x is not visible at this level. In essence, variables can only be used at the same or deeper level. They cannot be used at a shallower level.

Ternary Operator

The ternary or conditional operator is a kind of if statement shorthand. It’s formed by using a question mark and a colon ( ? : ). It looks like this:

c ? a : b

where c is the condition and a and b are values. If c is true, a is the result. If c is false, b is the result. For example:

String s = (5 < 10) ? "grapefruit" : "pineapple";

The variable s will hold the result of the ternary operation. Since 5 < 10 is true, the first value “grapefruit” gets stored in s. The condition is in parentheses but this isn’t necessary, it’s just easier to discern. In the following example, the condition is false:

String s = (10 < 5) ? "grapefruit" : "pineapple";

Therefore, the second value “pineapple” gets stored in s.

The ternary operator shouldn’t be used liberally because it can be harder to read than a normal if statement. But in this case it is an appropriate choice as the equivalent if statement would look like this:

String s;

if (10 < 5) {
    s = "grapefruit";
}
else {
    s = "pineapple";
}

We’ll look at some applications of the ternary operator in later chapters.

switch Statements

The switch statement is like a specialised if statement. It can be useful when you want to compare a single variable against several values. For example, imagine a classic vending machine that dispenses food items when you enter a code. This program simulates that behaviour:

import java.util.Scanner;

public class SwitchStatement {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("=== Vending Machine ===");
        System.out.println("351 - Plain Crisps");
        System.out.println("705 - Milk Chocolate");
        System.out.println("553 - Flapjack");
        System.out.println("270 - Lemonade");
        System.out.println("899 - Sparkling Water");
        System.out.println("000 - Shutdown");

        System.out.print("Code: ");
        String code = sc.next();

        switch (code) {
            case "351":
                System.out.println("Plain Crisps dispensed.");
                break;
            case "705":
                System.out.println("Milk Chocolate dispensed.");
                break;
            case "553":
                System.out.println("Flapjack dispensed.");
                break;
            case "270":
                System.out.println("Lemonade dispensed.");
                break;
            case "899":
                System.out.println("Sparkling Water dispensed.");
                break;
            default:
                System.out.println("Code not recognised.");
                break;
        }
    }
}

Line 5 creates a Scanner. Lines 6-12 displays information about the products to the user. Lines 14 and 15 obtain a code from the user in form of a String, which is stored in variable code. Next is a switch statement that starts on line 17 and ends on line 36. We can see it starts with the word switch. After this are some parentheses that contain the variable you want it to act on, in this case code. Following this are a bunch of cases that run depending on the value of code. For instance, the case on line 21 runs if code is “705” and line 22 prints “Milk Chocolate dispensed.” switch statements use the break keyword, which causes the switch statement to end right there and then, and the program continues at the point after the switch statement (line 36). Without a break, the program would continue executing code in subsequent cases until it hits a break or until it reaches the end of the switch statement itself. This is why breaks are necessary at the end of every case. There is also the default case on line 33. This runs if none of the other cases match, which makes it similar to the else block in an if statement. Here are a couple run-throughs:

[Run 1]
=== Vending Machine ===
351 - Plain Crisps
705 - Milk Chocolate
553 - Flapjack
270 - Lemonade
899 - Sparkling Water
000 - Shutdown
Code: 899
Sparkling Water dispensed.

Code 899 matches the case on line 30. Line 31 “dispenses” water and line 32 breaks to end the switch statement.


[Run 2]
=== Vending Machine ===
351 - Plain Crisps
705 - Milk Chocolate
553 - Flapjack
270 - Lemonade
899 - Sparkling Water
000 - Shutdown
Code: 510
Code not recognised.

Code 510 does not match any case so the default case runs on line 33 and the machine informs the user that the code is not recognised. Technically the break on line 34 is not needed since the switch statement would end anyway but at least it makes it look consistent.