Suggested reading: sections 5.1-5.9

Introduction to Loops

In chapter 3 we saw that the if-else construct enables us to equip our programs with the ability to make decisions. In chapter 5 we are going to see a variety of constructs that allow us to build repetition into our programs.

The while loop

The basic repetition construct in Java is the while loop. Its basic structure is as follows.

while(<test>) {
  <statements to be repeated>
}

When program execution first reaches the while statement, the test gets evaluated. If the test evaluates to true, execution enters the body of the loop and the statements inside the pair of curly braces gets executed. After execution of the body statements, we return again to the test. If the test evaluates to true again, we make another pass through the body. This process repeats until eventually the test evaluates to false. At that point, execution continues with the next statement after the body.

When writing a while loop you have to take care to ensure that the statements in the body will allow you to eventually reach a state where the loop test evaluates to false. If not, your program will stay stuck in the loop forever. (This condition is known as an infinite loop.)

A basic example: validation

One immediate application for the while loop is to implement a validation check for inputs. Here is an example based on the first programming assignment. Since the wind chill formula only works correctly for temperatures in a certain range and wind speeds greater than 2 mph, we have to check the temperature and wind speed the user inputs.

The example code below shows how to use a while loop to keep asking the user for input until they enter a valid input.

package windchill;

import java.util.Scanner;

public class WindChill {

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        double t,v,wct;

        System.out.print("Enter a temperature in Fahrenheit: ");
        t = input.nextDouble();
        while(t < -58 || t > 41) {
           System.out.println("The temperature must be in the range from -58 F to 41 F.");
           System.out.print("Enter a temperature in Fahrenheit: ");
           t = input.nextDouble();
        }

        System.out.print("Enter a wind speed in mph: ");
        v = input.nextDouble();
        while(v < 2) {
            System.out.println("The wind speed must be greater than 2 mph.");
            System.out.print("Enter a wind speed in mph: ");
            v = input.nextDouble();
        }

        wct = 35.74 + 0.6215*t -35.75*Math.pow(v, 0.16)+0.4275*t*Math.pow(v,0.16);

        System.out.println("The wind chill temperature is " + wct);
    }

}

Loop counter variables

One of the more common applications of loops uses an integer variable called a loop counter to control the behavior of the loop. Here is a typical example - in this example the loop counter simply ensures that the loop repeats the desired number of times.

public static void main(String[] args) {
  int n = 0;
  while(n < 10) {
    System.out.println("Hello!");
    n = n + 1;
  }
}

The variable n in the example acts as the loop counter. Before we enter the loop we give n an initial value of 0. The loop test monitors the current value of n and stops the repetition when n reaches the value 10. Finally, the last statement in the loop ensures that the value of n goes up by 1 on each trip through the loop. This guarantees that the loop will eventually terminate.

The statement

n = n + 1;

is commonly referred to as an increment statement. It causes the value stored in n to increase by 1 each time we evaluate the statement. This is such a common type of statement that Java offers a convenient short-cut form:

n++;

that does the same thing.

Frequently the counter variable is also used for more than just counting how many repetitions we have made. Frequently the thing we are trying to compute on each iteration of the loop depends in some way on the current value of the loop counter. Here is an example to illustrate this: the goal of the code below is to print a table of values for 2n as n ranges from 0 to 14.

public static void main(String[] args) {
  int n,power;
  n = 0;
  while(n < 15) {
    power = (int) Math.pow(2, n);
    System.out.println("2 to the power " + n + " is " + power);
    n++;
  }
}

Notice that the thing being printed is 2n, which of course depends on the current value of n.

Printing a table

Here is another example of using a loop to print a table of values. This version of the wind speed program has the user input a temperature and then uses a loop to print a table of wind chill temperatures for wind speeds ranging from 2 mph up to 20 mph in steps of 2 mph.

package windchill;

import java.util.Scanner;

public class Table {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        double t,v,wct;

        System.out.print("Enter a temperature in Fahrenheit: ");
        t = input.nextDouble();
        while(t < -58 || t > 41) {
           System.out.println("The temperature must be in the range from -58 F to 41 F.");
           System.out.print("Enter a temperature in Fahrenheit: ");
           t = input.nextDouble();
        }

        // Print a table of wind speed and wind chill
        System.out.println("Wind Speed    Wind Chill");
        v = 2.0;
        while(v <= 20.0) {
            wct = 35.74 + 0.6215*t-35.75*Math.pow(v, 0.16)+0.4275*t*Math.pow(v,0.16);
            System.out.println(v + "        " + wct);
            v = v + 2.0;
        }
    }
}

This works, but produces a poorly formatted table. For example, on the input 10 F, this program prints a table that looks like

Wind Speed    Wind Chill
2.0        6.788387329176881
4.0        2.663795973321772
6.0        0.03030239145645819
8.0        -1.9445568983790018
10.0        -3.5402167842280603
12.0        -4.886925405592865
14.0        -6.05660500717706
16.0        -7.09341028962846
18.0        -8.026506209329085
20.0        -8.876220556825402

The key to gettting a nicer looking table is to exercise more control in the print statements. We can do this by using System.out.printf() in place of System.out.println(). printf stands for "print formatted". To use this command we use a combination of a format string and a list of variables to be printed. The format string is a block of text to be printed, and contains format specifiers. The format specifiers act as placeholders for the values we want to print. For each variable you want to print you will need a format specifier.

A typical format specifier looks like

%8.2f

This specifier says to print a floating point number so that the number occupies a total of 8 columns in the printed output with 2 digits after the decimal point. If the number you are printing requires fewer than 8 characters, the output will be padded with extra spaces on the left to make the entire number take up exactly 8 characters.

Here now is an improved version of the print statement to use in the loop that prints the table of wind speeds:

System.out.printf("%8.2f   %8.2f\n",v,wct);

With this change the program prints a much nicer looking table of wind chills for 10 F.

Wind Speed  Wind Chill
    2.00       6.79
    4.00       2.66
    6.00       0.03
    8.00      -1.94
   10.00      -3.54
   12.00      -4.89
   14.00      -6.06
   16.00      -7.09
   18.00      -8.03
   20.00      -8.88

You can read more about the printf() command and format specifiers in section 4.6 of the textbook.

Using a loop to search

A common application of loops is to conduct a systematic search through a range of values looking for a value that satisfies some special condition. An example of an application where this is useful is the problem of finding divisors for an integer. To test whether an integer d divides evenly into another integer n we can use this logic:

if(n%d == 0)
{
  // d divides into n
}

We can use this test in combination with a loop to find all of the integers that divide evenly into some integer n:

System.out.print("Enter a value for n: ");
int n = input.nextInt();

int d = n - 1;
while(d > 1) {
  if(n % d == 0)
    System.out.println(d);
  d--;
}

A closely related application is the problem of determining whether or not a number is prime. One way to determine this is to use the logic above and keep a count of how many divisors we find:

System.out.print("Enter a value for n: ");
int n = input.nextInt();

int d = n - 1;
int divisorCount = 0;
while(d > 1) {
  if(n % d == 0)
    divisorCount++;
  d--;
}

if(divisorCount == 0)
  System.out.println("The number " + n + " is prime.");
else
  System.out.println("The number " + n + " is not prime.");

Application - adding things up

A common application that while loops are useful for is adding up lists of numbers. If the numbers to be added follow a simple and predictable pattern, it is relatively easy to write the logic needed to add the numbers up.

Here is a simple example. Suppose we wanted to compute the sum

for some integer N. The following code does that calculation.

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

  System.out.println("Enter a value for N: ");
  int N = input.nextInt();

  double sum = 0.0;
  int n = 1;
  double term;
  while (n <= N) {
    term = 1.0/n;
    sum = sum + term;
    n++;
  }

  System.out.println("The sum is " + sum);
}

In addition to the usual loop counter variable, n, which counts the number of terms we have added to the sum, we also use a second variable, sum, that stores the running total. On each iteration of the loop we compute the next term to be added to the sum, add it to the running total, and then increment the counter. If the relationship between the loop counter and the term we are trying to generate is simple, this strategy is very easy to implement.

In the next example, the relationship between the loop counter and the term we are adding to the running total gets a little more complicated. In this example, we want to compute the sum

where

N ! = N * (N-1) * (N-2) * ⋯ * 2 * 1

is the factorial of N. Those of you who have had Math 150 may know that in the limit as N gets very large this sum converges to e = 2.71828182846...

It is easy to see that if the loop counter for this sum runs from n = 1 up to n = N, the term we need to add to the running total when the counter is n is 1/n!. The problem is that we have no easy way to compute n!.

The solution to this difficulty is to reuse the strategy we used with powers earlier. If we just got done computing 1/n! and we have that result stored in a variable named term, we can easily compute 1/(n+1)! by computing term/(n+1).

The following code implements these ideas to correctly compute the sum.

public static void main(String[] args) {
  int n, N;
  double term, sum;

  System.out.print("Enter the number of terms: ");
  Scanner input = new Scanner(System.in);
  N = input.nextInt();

  n = 1;
  sum = 1.0;
  term = 1.0;
  while (n <= N) {
    sum = sum + term;
    // Compute the next term
    n++;
    term = term / n;
  }

  System.out.println("Sum = " + sum);
  System.out.println("e = " + Math.E);
}

Note that the logic here is somewhat touchy and difficult to get just right. In particular, the relative ordering of the statement that increments n and the statement that computes the new term matters greatly here.

One fairly effective way to tell whether or not you got the logic correct is to "play computer" and trace through the logic by hand. If you do that, you will see that the first term added to the sum is 1, the second term added is 1/2, and the third term is 1/6, as it should be.

Breaking out of a loop

Sometimes a search can terminate early when we find the thing we are looking for. In the last example, it doesn't make much sense to continue the search for divisors as soon as we find a valid divisor. For situations like this, we can use a break statement to exit a loop prematurely.

System.out.print("Enter a value for n: ");
int n = input.nextInt();

int d = n - 1;
while(d > 1) {
  if(n % d == 0)
    break;
  d--;
}

if(d == 1)
  System.out.println("The number " + n + " is prime.");
else
  System.out.println("The number " + n + " is not prime.");

Hitting a break statement anywhere in a loop will cause us to immediately exit the loop. That is appropriate in this situation, because we want to exit the loop as soon as we find a valid divisor.

The logic here takes advantage of the fact that if n is not prime we will encounter a valid divisor and break out of the loop before d has a chance to work its way down to 1.

do-while loops

One constraint that while loops have to operate under is that we have to be able to evaluate the test before entering the loop. This is sometimes a problem, because when we first encounter the test we may not have enough information to evaluate the test properly. To work around this problem, Java also offers an alternative loop structure, the do-while loop. Here is the basic structure of the do-while loop:

do {
  // Statements to be repeated
} while(<test>);

Like the while loop, the do-while loop repeats the statements in its body until the <test> is false. The difference in the do-while loop is that we get at chance to pass through the body of the loop before we have to evaluate the test. This is useful, because in some applications the <test> will not make sense until we have had a chance to do what the body statements do for us.

The do-while loop is often used to validate an input. Here is the wind speed calculation example again, this time with a slightly different approach to validating the input:

package windchill;

import java.util.Scanner;

public class WindChill {

    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        double t,v,wct;

        do {
          System.out.print("Enter a temp between -58 and 41: ");
          t = input.nextDouble();
        } while(t < -58 || t > 41);

        do {
          System.out.print("Enter a wind speed > 2 mph: ");
          v = input.nextDouble();
        } while(v < 2);

        wct = 35.74 + 0.6215*t-35.75*Math.pow(v, 0.16)+0.4275*t*Math.pow(v,0.16);

        System.out.println("The wind chill temperature is " + wct);
    }

}

for loops

The combination of a while loop and a loop counter variable is a very common configuration in programs:

int n = 0;
while(n < 100) {
  // Do something with n
  n++;
}

This code pattern appears so often in applications that all C family languages offer a convenient alternative called the for loop:

for(int n = 0; n < 100; n++) {
  // Statements to be repeated
}

The basic structure of a for loop is

for(<initialization>;<test>;<increment>) {
  <body>
}

This is completely equivalent to the structure

<initialization>
while(<test>) {
  <body>
  <increment>
}

and simply provides a more compact way to structure the loop.

Here is the wind chill table printing code reimplemented with a for loop instead of a while loop:

System.out.println("Wind Speed  Wind Chill");
for(v = 2.0; v <= 20.0; v = v + 2.0) {
    wct = 35.74 + 0.6215*t-35.75*Math.pow(v, 0.16)+0.4275*t*Math.pow(v,0.16);
    System.out.printf("%8.2f   %8.2f\n",v,wct);
}

Nested loops

In some cases we will find it necessary to put loops inside other loops. This occurs naturally where we have to perform some repeated task which itself requires a loop.

Here is an example from the text. This program prints a multiplication table:

public class MultiplicationTable {
  /** Main method */
  public static void main(String[] args) {
    // Display the table heading
    System.out.println("           Multiplication Table");

    // Display the number title
    System.out.print("    ");
    for (int j = 1; j <= 9; j++)
      System.out.print("   " + j);

    System.out.println("\n-----------------------------------------");

    // Print table body
    for (int i = 1; i <= 9; i++) {
      System.out.print(i + " | ");
      for (int j = 1; j <= 9; j++) {
        // Display the product and align properly
        System.out.printf("%4d", i * j);
      }
      System.out.println();
    }
  }
}

Since each row of the multiplication table has multiple entries, we will need a loop to print each row. That loop itself will sit inside another loop that works its ways down the rows of the table.

Here is another example involving a nested loop. We saw above how we could write some logic to determine whether or not an integer n is prime. We can easily convert this to code that scans through a range of integers looking for prime numbers. The logic below checks all of the odd numbers between 2 and 1000 and prints all of the prime numbers it finds.

int n = 3;
while(n < 1000) {
  int d = n - 1;
  while(d > 1) {
    if(n % d == 0)
      break;
    d--;
  }

  if(d == 1)
    System.out.println(n);

  n = n + 2;
}