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:
It internally generates a secret random integer number between 0 and 99;
It asks the user to guess the secret number, and reads the integer from the console;
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)
If the user’s guess is correct, the program congratulates the user and continues from point 6 below;
Otherwise, if the user’s guess is not correct:
if the user’s guess was the number -1, the program reveals the secret number and continues from point 6 below;
otherwise, the program prints whether the user’s guess was higher or lower than the correct answer, and repeats from point 2 above;
Finally, the program says goodbye to the user, and ends.
This behaviour is depicted in the following flowchart.
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.
(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 expressionguess > secret
is true o false. That string is then used to initialise the variable calledfeedback
. 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:
bool_expr
is evaluated;then, the result if
bool_expr
is checked:if the result of
bool_expr
is the valuetrue
, 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 thewhile
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 valuefalse
), 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.
(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?
(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}
(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)
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)
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 resulttrue
if there is an input available that has the format of anint
value — and therefore, we can retrieve that value by callings.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 resultfalse
if the user has writtenHi!
or3.14
on the terminal; orthe input stream has been closed, hence no further inputs will become available, as described in Remark 12 below.
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 valuetrue
: 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 valuefalse
: 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.
(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.
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:
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 thedo-while
loop and continues with the statements (if any) that follow it (line 4);
then,
bool_expr
is evaluated;then, the result if
bool_expr
is checked:if the result of
bool_expr
is the valuetrue
, then the execution continues (or “loops”) by going back to point 1 above;otherwise (i.e. if the result of
bool_expr
is the valuefalse
), 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.
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.
(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
For each assessment, you can download the corresponding handout and submit your solution on DTU Autolab: https://autolab.compute.dtu.dk/courses/02312-E24.
For details on how to use Autolab and the assessment handouts, and how to submit your solutions, please read these instructions.
If you have troubles, you can get help from the teacher and TAs.
07 - Password Check 2#
Edit the file Password.java
provided in the handout, and write a program that:
reads a
String
from the console, representing a password; andchecks 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 ⏎
.
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
You may use the
Scanner
objects’ method.hasNextLine()
to check whether the program input stream has been closed.You may consider using a switch statement (see also Example 19).
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 "#"
…