Module 3, Part 2: Loops#

In this module we address loops, i.e., how to write Java programs that repeat the execution of some statements based on a (boolean) conditions. More specifically, we focus on two control flow statements:

We have already seen the notion of a “loop” when programming BlinkenBits, where we can use the instruction if … jump … to jump back to a previously-executed part of the code if a certain condition is true (see e.g. Example 6). However, when programming in BlinkenBits assembly we had to consider which register to check for deciding whether to jump, and which exact memory location the computer should jump to. These details make assembly programs hard to write, read, and maintain — especially because programming using explicit jumps (also called “GOTOs” in some programming languages) quickly leads to spaghetti code.

When we write a loop in Java, these details are handled automatically behind the scenes, as the Java code is translated into machine instructions. Therefore, we can focus on higher-level aspects: which statements of our program may need to be repeated, and what is the (boolean) condition for repeating them.

To see what Java loops look like and how they can be used, let us consider a practical problem: writing an interactive program that asks the user to guess a number.

Goal: a Program that Lets the User Guess a Number#

Our goal is to write a program that runs on the console (a.k.a. terminal) and behaves as follows:

  1. It internally generates a secret random integer number between 0 and 99;

  2. It asks the user to guess the secret number, and reads the integer from the console;

  3. If the user closes the input stream, or the user writes something that is not an integer, the program continues from point 6 below. (We will see the meaning of “closing the input stream” shortly)

  4. If the user’s guess is correct, the program congratulates the user and continues from point 6 below;

  5. Otherwise, if the user’s guess is not correct:

    1. if the user’s guess was the number -1, the program reveals the secret number and continues from point 6 below;

    2. otherwise, the program prints whether the user’s guess was higher or lower than the correct answer, and repeats from point 2 above;

  6. Finally, the program says goodbye to the user, and ends.

This behaviour is depicted in the following flowchart.

Flowchart for the number guessing program

Based on the elements of Java we have covered so far, we can see that the description above requires some conditional checks on some expression of type boolean (e.g. comparing the user’s number with the random number, on point 4 above). However, we have not yet seen how to:

  • Generate random numbers;

  • Re-execute part of a program depending on some condition (see point 5.2 above, and the looping-back arrow at the top of the highlighted part of the flowchart); and

  • Check whether the input stream contains unexpected data or has been closed.

We will see that generating random numbers and checking the input stream are not difficult issues. Instead, re-executing parts of a program multiple times (based on a condition) requires us to use a new concept: control flow statements for loops.

Example 20 (A number-guessing program)

The following Java program behaves according to the description above, and uses some Java constructs that we have not yet seen. In the rest of this module we will discuss such constructs.

Note

  • You can run the program below by copy&pasting it in a text editor (e.g. VS Code), saving it in a file called Guess.java, and then running on a terminal (in the same folder where you saved the file):

    java Guess.java
    
  • On line 23, the program below uses a conditional expression that produces a string which can be either "too high" or "too low" depending on whether the result of the expression guess > secret is true o false. That string is then used to initialise the variable called feedback. The same effect can be achieved by using an if-then-else statement instead. (Try it as an exercise!)

 1class Guess {
 2    public static void main(String[] args) {
 3        // Create a random number generator
 4        var rnd = new java.util.Random();
 5        // Generate a random integer between 0 (included) and 100 (excluded)
 6        var secret = rnd.nextInt(100);
 7
 8        System.out.println("Hi, human.  I have a secret number in my mind.");
 9        System.out.println("Try to guess it!");
10
11        var scanner = new java.util.Scanner(System.in);
12        scanner.useLocale(java.util.Locale.ENGLISH);
13
14        while (scanner.hasNextInt()) {
15            var guess = scanner.nextInt();
16            if (guess == secret) {
17                System.out.println("Your guess is correct!  Well done!");
18                break;
19            } else if (guess == -1) {
20                System.out.println("The secret number was: " + secret);
21                break;
22            }
23            var feedback = (guess > secret) ? "too high" : "too low";
24            System.out.println("Your guess was " + feedback + ".  Try again!");
25        }
26
27        scanner.close();
28        System.out.println("Goodbye!");
29    }
30}

Interlude: Generating Random Numbers#

Before delving into the main topics of this module, let us address an easy part of Example 20: the creation of a random number.

Observe that, on line 4, the program in Example 20 declares a variable rnd by creating a new object of the class java.util.Random; then, on line 6, the program calls the method rnd.nextInt(100) that produces a random int number between 0 (included) and 100 (excluded).

The way we create and use the object of type java.util.Random is similar to how we create and use objects of the class java.util.Scanner — but of course, objects of the class Random serve a different purpose, and have different methods.

Note

The class java.util.Random is part of the Java API; if you are curious, you can have a look at its official documentation.

While Statement#

The while statement (or “while loop”) in Java has the following syntax:

1while (bool_expr) {
2    // Statements that are executed at each loop repetition
3}
4// Other statements can follow (optionally)

where bool_expr is called the loop condition, and can be any expression of type boolean. The while statement is executed as follows:

  1. bool_expr is evaluated;

  2. then, the result if bool_expr is checked:

    • if the result of bool_expr is the value true, then:

      • the statements in the pair of curly brackets {} (lines 1–3) are executed; (that block of statements is called the loop body)

      • if one of such statements is break, the execution exits from the while loop and continues with the statements (if any) that follow it (line 4);

      • otherwise (i.e. if no break is encountered), the execution continues (or “loops”) by going back to point 1 above;

    • otherwise (i.e. if the result of bool_expr is the value false), the execution continues with the statements (if any) that follow the “while” loop (line 4).

When represented as a flowchart, the while statement looks as follows — where the highlighted part (excluding the loop condition bool_expr) is the loop body. Whenever we spot the following pattern in a flowchart, we should consider using a while statement when writing the corresponding Java program.

Flowchart for "while" loop

Remark 10 (Beware of infinite loops!)

The description above means that the “while” loop will repeat as long as the expression bool_expr produces the result true when evaluated. If that expression always evaluates to true, the loop will keep repeating forever (as in Example 21 below) — unless the loop body executes a break statement (as in Example 23 below).

Infinite loops may be useful or not, depending on the goals of a program. When designing and writing your code, take the following into consideration:

  • Are there situations where a loop you wrote may run forever?

  • If the answer is “yes,” is the infinite loop part of the program requirements? Or, is it just a bug?

Example 21 (An infinite loop on the Java shell)

If you try to copy&paste and execute the following code on the Java shell, it will loop forever — because the loop condition 0 < 3 evaluates to true every time it is checked. Consequently, this code will print Greetings from the loop body! over and over.

Important

To interrupt the execution of the following code under the Java shell, press Ctrl+C. In most cases, you can use Ctrl+C to interrupt the execution of any program running on a terminal.

1while (0 < 3) {
2    System.out.println("Greetings from the loop body!");
3}

Example 22 (A finite loop on the Java shell)

Let us modify the code in Example 21 so that the loop is only repeated 3 times. We have different ways to do it: one is described here, and another in Example 23 below.

We can make the result of the loop condition expression depend on the value of a variable: this way, we can control the loop repetition by changing the value of that variable. For instance:

1var i = 0;
2while (i < 3) {
3    System.out.println("Greetings from the loop body! (i == " + i + ")");
4    i = i + 1;
5}
6System.out.println("The loop is over! (i == " + i + ")");

Here we are using the variable i as a counter: we initialise it with value 0, and we increment its value every time the loop body runs (line 4). Consequently, the expression i < 3 will evaluate to true when i is either 0, 1, or 2 — but will evaluate to false when i reaches the value 3. When this happens, the while loop stops repeating, and the execution continues with the statements that follow (line 6).

If you try to copy&paste and execute the code above on the Java shell, it will print the following output:

Greetings from the loop body! (i == 0)
Greetings from the loop body! (i == 1)
Greetings from the loop body! (i == 2)
The loop is over! (i == 3)

Example 23 (A finite loop on the Java shell, using break)

Let us write a while loop similar to the one in Example 22, but using a different style. Here we write a potentially infinite loop where the loop condition always evaluates to true — but we stop the loop by using a break statement in the loop body (when a certain condition is met).

 1var i = 0;
 2while (true) {
 3    if (i == 3) {
 4        System.out.println("Breaking the loop! (i == " + i + ")");
 5        break;
 6    }
 7    System.out.println("Greetings from the loop body! (i == " + i + ")");
 8    i = i + 1;
 9}
10System.out.println("The loop is over! (i == " + i + ")");

As in Example 22, here we are using the variable i as a counter: we initialise it with value 0, and we increment its value every time the loop body runs (line 8). However (unlike Example 22), here the loop condition is always true, so the loop will keep repeating regardless of the value of i. Consequently, we manually check whether the counter has reached the desired value (line 3) — and if so, we execute a break statement (line 5). When this happens, the while loop stops repeating, and the execution continues with the statements that follow (line 10).

If you try to copy&paste and execute the code above on the Java shell, it will print the following output:

Greetings from the loop body! (i == 0)
Greetings from the loop body! (i == 1)
Greetings from the loop body! (i == 2)
Breaking the loop! (i == 3)
The loop is over! (i == 3)

Remark 11 (Using break statements vs. program clarity)

When writing loops, using the break statement is sometimes necessary — but in general, break statements can make the program logic more complicated: every break introduces a new exit point for the loop execution, and makes it harder to understand when and how a loop may terminate. This increases the chances of introducing bugs in your program.

Therefore, the advice is: when you design and write your loops, whenever the break statement seems necessary, take some time and think whether you can revise your code in a way that achieves the same goals without using break.

For instance, if your code starts looking like Example 23, take some time to consider whether it could be simplified to look more like Example 22.

Looping as Long as More Inputs Are Available#

Objects of the class java.util.Scanner include some very handy methods that are often used as loop conditions, to make a program loop as long as there are more inputs to process. If s is an object of type java.util.Scanner, these methods are:

  • s.hasNextInt()

  • s.hasNextDouble()

  • s.hasNextLine()

These methods behave similarly: when called, they wait (block) until an input becomes available from the console, and then they produce a boolean value as a result. This result may be:

  • true if the available input conforms to the desired format. E.g. s.hasNextInt() produces the result true if there is an input available that has the format of an int value — and therefore, we can retrieve that value by calling s.nextInt();

  • otherwise, the result is false. This may happen in two cases:

    • there is input available, but it has the wrong format. E.g. s.hasNextInt() gives the result false if the user has written Hi! or 3.14 on the terminal; or

    • the input stream has been closed, hence no further inputs will become available, as described in Remark 12 below.

Example 24 (Using the Scanner object method .hasNextInt() as loop condition, part 1)

The following code snippet creates an object of class java.util.Scanner to receive input from the terminal, and then loops as long as that input has the format of an integer value.

 1var s = new java.util.Scanner(System.in);
 2s.useLocale(java.util.Locale.ENGLISH);
 3
 4while (s.hasNextInt()) {
 5    var v = s.nextInt();
 6    System.out.println("Got an integer value: " + v);
 7}
 8
 9System.out.println("Unable to get another integer!");
10s.close();

You can copy&paste and execute the code above on the Java shell. If you try, the while loop will evaluate the loop condition expression s.hasNextInt(), which blocks until you write something on the console and press . Then:

  • if you write an integer, then s.hasNextInt() produces the value true: therefore, the loop body will be executed, and the loop will go back to evaluating its condition, which will block waiting for the next input;

  • if you write something that is not an integer, then s.hasNextInt() produces the value false: the loop ends and the execution continues with the statements that follow it.

So for example, if you write 42 and press , the program will print:

Got an integer value: 42

Then, the program will wait for the next input. You can also write multiple numbers separated by spaces. For instance, if you write:

10 20 30 40

and press , the program will print:

Got an integer value: 10
Got an integer value: 20
Got an integer value: 30
Got an integer value: 40

You can end the loop by writing something that is not an integer. For example, if you write:

1234 5678 Bye!

and press , the program will print:

Got an integer value: 1234
Got an integer value: 5678
Unable to get another integer!

Hence the loop will stop, and you will see the Java shell prompt again.

Remark 12 (Closing the default input stream of a program)

When you run a program on a terminal, you can close its standard input stream by pressing Ctrl+D.

Note

On Windows, if Ctrl+D does not work, you may try instead to press Ctrl+Z, and then .

When the standard input stream is closed, no further inputs will be delivered to the program from the console. The program can notice the event and react accordingly: for instance, if you try the key combinations above at the Java shell prompt, the Java shell will terminate.

Your Java programs can detect the event by using the Scanner object methods .hasNextInt(), .hasNextDobule(), etc. However, this will not work as expected if you execute your code under the Java shell! You will need to save your program in a .java file and run it directly from the terminal, as shown in Example 25 below.

Example 25 (Using the Scanner object method .hasNextInt() as loop condition, part 2)

Let us now turn the code snippet in Example 24 into an actual Java program:

 1class InputLoop {
 2    public static void main(String[] args) {
 3        var s = new java.util.Scanner(System.in);
 4        s.useLocale(java.util.Locale.ENGLISH);
 5
 6        while (s.hasNextInt()) {
 7            var v = s.nextInt();
 8            System.out.println("Got an integer value: " + v);
 9        }
10        System.out.println("Unable to get another integer!");
11
12        s.close();
13    }
14}

You can copy&paste the program above in a text editor (e.g. VS Code), save it in a file called InputLoop.java, and run it by executing on a terminal (in the same folder where the file is saved):

java InputLoop.java

Then you can experiment with the inputs described in Example 24. You can also try closing the standard input (by pressing Ctrl+D): you will see that the loop stops and the program terminates, because s.hasNextInt() produces false when the standard input is closed.

Note

On Windows, if Ctrl+D does not work, you may try instead to press Ctrl+Z, and then .

Do-While Statement#

A while loop can execute its loop body zero or more times, depending on whether the loop condition evaluates to true or false. However, there cases where we may need to execute the loop body at least once. For these situations, Java provides the do-while statement (or “do-while loop”), with the following syntax:

1do {
2    // Statements that are executed at each loop repetition
3} while (bool_expr);
4// Other statements can follow (optionally)

The do-while statement is executed as follows:

  1. the statements in the pair of curly brackets {} (lines 1–3) are executed; (that block of statements is called the loop body)

    • if one of such statements is break, the execution exits from the do-while loop and continues with the statements (if any) that follow it (line 4);

  2. then, bool_expr is evaluated;

  3. then, the result if bool_expr is checked:

    • if the result of bool_expr is the value true, then the execution continues (or “loops”) by going back to point 1 above;

    • otherwise (i.e. if the result of bool_expr is the value false), the execution continues with the statements (if any) that follow the “while” loop (line 4).

In other words, the do-while loop executes its body once; after that, its behaviour is similar to a while loop (i.e. it will only execute the body again if the loop condition evaluates to true).

When represented as a flowchart, the do-while statement looks as follows — where the highlighted part (excluding the loop condition bool_expr) is the loop body. Whenever we spot the following pattern in a flowchart, we should consider using a do-while statement when writing the corresponding Java program.

Flowchart for "do-while" loop

Example 26 (A do-while loop)

Suppose we need to write a program that requires the user to provide a int value within a certain range, and we want to repeat the request until the user provides a valid answer. We can solve the problem using a do-while loop as follows: (you can execute this code snippet on the Java shell)

 1var s = new java.util.Scanner(System.in);
 2s.useLocale(java.util.Locale.ENGLISH);
 3
 4var height = 0;
 5do {
 6    System.out.println("Please write your height in cm (between 10 and 300)");
 7    height = s.nextInt();
 8} while ((height < 10) || (height > 300));
 9
10System.out.println("Your height is: " + height + " cm");
11s.close();

Concluding Remarks#

You should now have an understanding of how to execute one or more statements repeatedly, depending on the result of a boolean expression, by using While Statement or Do-While Statement.

You should also know how to loop as long as more inputs are available and check whether the program input stream has been closed.

With this knowledge, you should be able to understand each line of the program in Example 20.

References and Further Readings#

You are invited to read the following sections of the reference book: (Note: they sometimes mention Java features that we will address later in the course)

  • Section 5.4 - “The while Statement”

  • Section 6.3 - “The do Statement”

Exercises#

Note

These exercises are not part of the course assessment. They are provided to help you self-test your understanding.

Exercise 23 (Does this loop terminate?)

The following code snippets contain some loops: read each one, and try to determine whether it terminates. To check whether your guess is correct, run the loop in the Java shell — and remember that you can interrupt the execution of a loop by pressing Ctrl+C.

  • var i = 0;
    while (i != 10) {
        System.out.println("i == " + i);
        i = i + 2;
    }
    
  • var i = 1;
    while (i != 10) {
        System.out.println("i == " + i);
        i = i + 2;
    }
    
  • var i = 1;
    while (i < 10) {
        System.out.println("i == " + i);
        i = i + 2;
    }
    
  • var i = 2;
    while (i < 2) {
        System.out.println("i == " + i);
        i = i - 2;
    }
    
  • var i = 2;
    do {
        System.out.println("i == " + i);
        i = i - 2;
    } while (i < 2)
    
  • var i = 2;
    do {
        System.out.println("i == " + i);
        i = i - 2;
    } while (i > 0)
    

Lab and Weekly Assessments#

During the lab you can try the exercises above or begin your work on the weekly assessments below.

Important

07 - Password Check 2#

Edit the file Password.java provided in the handout, and write a program that:

  1. reads a String from the console, representing a password; and

  2. checks the length of the password: if the length is between 5 and 8 characters, the program prints Password length OK and ends;

    • if the password is shorter than 5 characters, the program prints Password too short and goes back to point 1;

    • if the password is longer than 8 characters, the program prints Password too long and goes back to point 1.

When you are done, submit the modified file Password.java on DTU Autolab.

Hint

To solve this assessment, you can reuse most of the solution to 05 - Password Check, and introduce some form of loop…

08 - Animal Sounds#

Edit the file AnimalSounds.java provided in the handout, and write a program that reads the name of an animal from the terminal, and:

  • if the animal name is one of those listed in Table 8 below, the program prints the corresponding sound;

  • otherwise (i.e. if the animal name is not listed in the table) the program prints ?.

The program must keep reading animal names and printing sounds (as explained above) until the standard input stream is closed (by pressing Ctrl+D).

Note

On Windows, if Ctrl+D does not work, you may try instead: Ctrl+Z, and then .

Table 8 Animal sounds#

Animal name

Sound

Dog

Woof

Cat

Meow

Sheep

Baa

Cow

Moo

Lion

Roar

Pig

Oink

Duck

Quack

When you are done, submit the modified file AnimalSounds.java on DTU Autolab.

Hint

09 - Square#

Edit the file Square.java provided in the handout, and write a program that reads from the console an integer value \(n\) and prints a square of size \(n \times n\), using the character #.

You can assume that \(n\) is not negative (but it can be zero!).

For example, if program reads the value 3, it must print:

###
###
###

When you are done, submit the modified file Square.java on DTU Autolab.

Hint

For this assignment, it might be handy to use Some Useful String Methods to create a string that consists of \(n\) repetitions of "#"