Lecture 24: While loops
While loops for unbounded iteration
24.1 While loops
In the last few lectures we’ve been discussing looping constructs, which let us repeat a block of statements some number of times. The for-each loop let us repeat the block once per item in an ArrayList, while the counted-for loop let us repeat the block for each value of some index variable as it counted from a starting value to a final value. There is one more loop construct in Java, which is more flexible than either the for-each loop or the counted-for loop, known as a while loop.
A while loop simply repeats a block of code for as long as its termination condition remains true:
while (someBooleanExpression()) { ...body of loop... }
while(false) { doSomethingWith(1 / 0); }
To show that while loops are more flexible than the other forms of loops, we first show how to use this loop to express the exact same computation as a counted-for loop. Then, we give examples of loops that cannot be expressed as counted-for loops.
24.1.1 Translating a counted-for loop into a while loop
for (int idxVar = start; idxVar < end; idxVar = idxVar + 1) { ...body... }
... while (idxVar < end) { ... } ...
... while (idxVar < end) { ...body... idxVar = idxVar + 1; } ...
int idxVar = start; while (idxVar < end) { ...body... idxVar = idxVar + 1; }
All four pieces of the counted-for loop are present (initialization, termination condition, body, and update statement), and they serve exactly the same purpose within this style of while loop as they do in a counted-for loop.
Do Now!
Translate the code of findMin to use a while loop instead of a counted-for loop.
But when can while loops be more general?
24.1.2 The 3n+1 problem
This puzzle is properly known as the Collatz conjecture, and is an unsolved problem in pure mathematics.
\begin{equation*}f(n) = \begin{cases} n / 2 &\text{when $n$ is even} \\ 3n + 1 &\text{when $n$ is odd} \end{cases}\end{equation*}
9 -> 28 -> 14 -> 7 -> 22 -> 11 -> 34 -> 17 -> 52 -> 26 |
-> 13 -> 40 -> 20 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1 |
// In some Utils class boolean getsToOne(int n) { while (n > 1) { if (n % 2 == 0) { n = n / 2; } else { n = 3 * n + 1; } } return true; }
Exercise
Try elaborating the function above to keep track of this extra information.
24.1.3 Big-bang
How does the big-bang library work? Conceptually, it takes an initial world and invokes the makeImage method to create an image from it, then invokes the onTick method to get the next work, and then repeats these two steps until the worldEnds method returns true. This sounds like looping behavior, but it cannot possibly be a counted-for loop, since the game can last an indefinite amount of time, and we’re not counting any particular index, but rather updating a world from one value to the next. This is a perfect use of a while loop. In fact, this style of using a while loop to repeatedly handle events (such as keypresses or mouse clicks) is at the core of almost every operating system, browser, game console, or other system that deals with interactivity.
24.2 Discussion
When should we use each of these three loop types? After all, if every for-each loop over ArrayLists can be rewritten to use a counted-for loop, and every counted-for loop can be rewritten to use while loops, why bother with the other two loops?
To a large extent, this is an aesthetic choice, and programmers largely have come to consensus on when it is appropriate to use each of these loops. The shortest guideline is, “use the simplest form loop that works”. If a problem can be expressed as a computation over the particular items of an ArrayList, use a for-each loop. If the problem requires specifically manipulating indices, or counting for whatever reason, use a counted-for loop. If the number of iterations of the loop is not known a priori, use a while loop.
Additionally, as we will see in the next lecture, for-each loops are in fact more general than just working with ArrayLists, and we will encounter additional reasons to use them.