Chapter 5
Indefinite Loops and Program Logic

Copyright © 2004 by Stuart Reges

5.1 Introduction

The chapter begins by examining a new construct called a while loop that allows you to loop an indefinite number of times. Then it discusses the type boolean in greater detail. Then it explores what are known as assertions and their relationship to understanding the logic of programs. It ends with a discussion of other loop constructs available in Java.

5.2 While Loops

The loops we have looked at so far have been fairly simple loops that execute a predictable number of times. We call them "definite" loops because you know before the loop begins executing exactly how many times it will execute. Now we want to turn our attention to indefinite loops where you don't know how many times a loop will execute. These come up often in interactive programs and file processing. For example, you don't know in advance how many times a user might want to play a game and you won't know before you look at a file exactly how much data it stores.

The while loop is the first indefinite loop we will study. It has the following syntax:

while (<test>) <statement>; The while loop performs its test and, if the test evaluates to true, executes the controlled statement. It continually tests again and executes again if the test evaluates to true. Only when the test evaluates to false does the loop terminate.

Here is an example of a while loop.

    int number = 1;
    while (number <= 200)
	number *= 2;
Recall that the "*=" operator says to "multiply the variable by" a certain amount, in this case multiplying the variable by 2. Thus, this loop initializes an integer variable called number to 1 and then doubles it while it is less than or equal to 200. On the surface, this looks like the following.

    int number = 1;
    if (number <= 200)
	number *= 2;
The difference between the two is that the while loop executes multiple times. It loops until the test returns false. The if statement executes the doubling statement once, leaving number equal to 2. The while loop executes the doubling statement indefinitely until the test returns false. This while loop executes the assignment statement eight times, setting number to the value 256 (the first power of 2 that is greater than 200).

The while loop tests its condition before executing the statement it controls. It performs its test at the top of the loop, as indicated in this pseudocode.

    loop
        evaluate test.
        if test returns false then exit.
        execute controlled statement.
    end of loop
Notice that a while loop will not execute its controlled statement if its test returns false the first time it is evaluated.

Here is a while with two statements in the loop.

    int number = 1;
    while (number <= max) {
	System.out.println("Hi there");
	number++;
    }
As with the for loop and if/else statement, you use curly braces to form a block when you want to control more than one statement. This loop executes a println statement repeatedly and increments number until is is greater than max. This while loop is more or less equivalent to the following for loop.

    for (int number = 1; number <= max; number++)
	System.out.println("Hi there");
Suppose you want to find the smallest divisor of a number other than 1. Here are some examples of what you are looking for:

Number Factors Smallest Divisor
102 * 52
153 * 53
255 * 55
313131
777 * 117

Here is a pseudocode description of how you might do this.

	start divisor at 2.
	while (the current value of divisor does not work)
	    increase divisor.
You don't start divisor at 1 because you are looking for the first divisor greater than 1. To modify this code you must be more explicit about what makes a divisor work. A divisor of a number has no remainder when the number is divided by it. You can rewrite this as:

	start divisor at 2.
	while (the remainder of number/divisor is not 0)
	    increase divisor.
Here is a use for the mod operator which gives the remainder for integer division. The following while loop performs this task:

    int divisor = 2;
    while (number % divisor != 0)
	divisor++;
One problem you will undoubtedly encounter in writing your while loops is the infamous infinite loop. Consider the following code:

    int number = 1;
    while (number > 0)
	number++;
Because number begins as a positive value and the loop makes it larger, this loop will continue indefinitely. You must be careful in formulating your while loops to avoid situations where a piece of code will never finish executing. Every time you write a while loop you should consider when and how it will finish executing.

5.2.1 Fencepost Loops (aka loop and a half)

In programming we often find ourselves with a particular kind of loop known as a fencepost loop. To understand the concept, consider the following problem. You want to put up a fence that is 100 yards long and you want to have a post every 10 yards. How many posts do you need? If you do a quick division in your head, you might say that you need 10 posts, but actually you need 11 posts. That's because fences begin and end with posts. In other words, the fence looks like this:

    post, wire, post, wire, ..., post, wire, post
Because you want posts on both the far left and the far right, you can't use the following simple loop because it doesn't plant the final post.

    for (the length of the fence) {
        plant a post.
        attach some wire.
    }
Switching the order of the two operations doesn't help, because you miss the first post. The problem with this loop is that it produces the same number of posts as sections of wire, but we know we need an extra post. That's why this problem is also sometimes referred to as the "loop and a half" problem because we want to execute one half of this loop (planting a post) one extra time.

One solution is to plant one of the posts either before or after the loop. The usual solution is to do it before.

    plant a post.
    for (the length of the fence) {
        attach some wire.
        plant a post.
    }
Notice that the order of the two operations in the body of the loop is now reversed because the initial post is planted before you enter the loop.

As a simple example, consider the problem of writing out the integers between 1 and 10 separated by commas. In other words, we want to get this output:

1, 2, 3, 4, 5, 6, 7, 8, 9, 10 This is a classic fencepost problem because we want to write out 10 numbers but only 9 commas. In our fencepost terminology, writing a number is the "post" part of the task and writing a comma is the "wire" part. So implementing the pseudocode above, we print the first number before the loop:

    System.out.print(1);
    for (int i = 2; i <= 10; i++)
	System.out.print(", " + i);
    System.out.println();
The principle applies equally well to while loops, as we'll see in the next two sections.

5.2.2 Sentinel Loops

Suppose you want to read a series of numbers from the user and compute their sum. You could ask the user in advance how many numbers to read, but that isn't always convenient. What if the user has a long list of numbers to enter? One way around this is to pick some special input value that will signal the end of input. We call this a sentinel value.

Sentinel

A special value that signals the end of input.

For example, you could tell the user to enter the value -1 to stop entering numbers. But how do we structure our code to make use of this sentinel? In general, we want to do the following.

    sum = 0.
    while (we haven't seen the sentinel) {
	prompt & read.
	add it to the sum.
    }
But we don't want to add the sentinel value into our sum. This is a classic fencepost or loop-and-a-half problem. We want to prompt for and read the sentinel, but we don't want to add it to the sum. We can use the usual fencepost solution of doing the first prompt and read before the loop and reversing the order of the two steps in the body of the loop.

    sum = 0.
    prompt & read.
    while (we haven't seen the sentinel) {
	add it to the sum.
	prompt & read.
    }
We can refine this pseudocode by introducing a variable for the number that we read from the user:

    sum = 0.
    prompt & read a value into n.
    while (n is not the sentinel) {
	add n to the sum.
        prompt & read a value into n.
    }
This translates fairly easily into Java code.

    Scanner console = new Scanner(System.in);

    int sum = 0;
    System.out.print("next integer (-1 to quit)? ");
    int number = console.nextInt();
    while (number != -1) {
        sum += number;
        System.out.print("next integer (-1 to quit)? ");
        number = console.nextInt();
    }
    System.out.println("sum = " + sum);
When this code is executed, the interaction looks like this:

next integer (-1 to quit)? 34 next integer (-1 to quit)? 19 next integer (-1 to quit)? 8 next integer (-1 to quit)? 0 next integer (-1 to quit)? 17 next integer (-1 to quit)? 204 next integer (-1 to quit)? -1 sum = 282

5.2.3 Checking for User Errors

In the last chapter we wrote programs that assumed that the user would type appropriate values. In general, you want to write programs that don't make such assumptions. We saw, for example, that the Scanner object can throw an exception if the user types the wrong kind of data. It's better to write programs that can deal with user errors. Such programs are referred to as being robust.

Robust

A program is said to be robust if it is able to execute even when presented with illegal data.

Consider the following code fragment:

    Scanner console = new Scanner(System.in);
    System.out.print("How old are you in years? ");
    int age = console.nextInt();
What if the user types something that is not an integer? If that happens, the Scanner will throw an exception on the call to nextInt(). We saw in the last chapter that we can test whether or not the next token can be interpreted as an integer with the hasNextInt() method. So we can test before reading an int whether the user has typed an appropriate value.

What if the user types something other than an integer? Then we'd want to discard the input, print out some kind of error message and prompt for a second input. We'd want this in a loop so that we'd keep discarding input and generating error messages until the user gives us legal input. Here is a first attempt at a solution in pseudocode:

    while (user hasn't given us an integer) {
        prompt.
        discard input.
        generate an error message.
    }
    read the integer.
This reflects what we want to do in general. We want to keep prompting, discarding and generating an error message as long as the input is illegal and then we want to read the integer when the input finally becomes legal. But we don't want to discard the input or generate an error message in that final case where the user gives us legal input. In other words, the last time through the loop we want to do just the first of these 3 steps (prompting, but not discarding and not generating an error message). This is another classic fencepost problem and we can solve it in the usual way by putting the initial prompt before the loop and changing the order of the operations within the loop.

    prompt.
    while (user hasn't given us an integer) {
        discard input.
        generate an error message.
        prompt.
    }
    read the integer.
This is fairly easy to turn into Java code:

    Scanner console = new Scanner(System.in);
    System.out.print("How old are you in years? ");
    while (!console.hasNextInt()) {
        console.next();  // to discard the input
        System.out.println("That is not an integer.  Please try again.");
        System.out.print("How old are you in years? ");
    }
    int age = console.nextInt();
In fact, this is such a common operation that it is worth turning this into a static method:
    public static int getInt(Scanner console, String prompt) {
	System.out.print(prompt);
	while (!console.hasNextInt()) {
	    console.next();
	    System.out.println("That is not an integer.  Please try again.");
	    System.out.print(prompt);
	}
	return console.nextInt();
    }
Using this method, we can rewrite our original code to the following.

    Scanner console = new Scanner(System.in);
    int age = getInt(console, "How old are you in years? ");
When you execute this code, the interaction looks like this:

How old are you in years? what? That is not an integer. Please try again. How old are you in years? 18.4 That is not an integer. Please try again. How old are you in years? ten That is not an integer. Please try again. How old are you in years? darn! That is not an integer. Please try again. How old are you in years? help That is not an integer. Please try again. How old are you in years? 19

5.2.4 A loop with priming and pseudorandom numbers

We often want our programs to exhibit apparently random behavior. This often comes up in game playing programs where we need our program to make up a number for the user to guess or to shuffle a deck of cards or to pick a word from a list of words for the user to guess. Programs are, by their very nature, predictable and non-random. But we can produce values that seem to be random. Such values are called pseudorandom because they are produced algorithmically.

Pseudorandom numbers

Numbers that, although they are derived from a predictable and well-defined algorithm, mimic the properties of numbers chosen at random.

Java provides several mechanisms for obtaining pseudorandom numbers. You can call the method Math.random() from the Math class to obtain a random floating point value that has the property that:

0.0 <= Math.random() < 1.0 This is a quick and easy way to get a random number and you can use multiplication to change the range of the numbers produced. But Java provides a class called Random that can be easier to use. It is included in the java.util package, so you'd have to include an import declaration at the beginning of your program to use it. Once you construct a Random object, you can call its method nextInt passing it a maximum integer. The number returned will be between 0 (inclusive) and the maximum (exclusive). For example, if you call nextInt(100), you will get a number between 0 and 99. Obviously you can add 1 to the number to have a range between 1 and 100.

Let's look at a simple program that picks numbers between 1 and 10 until a particular number comes up. Let's use the Random class to construct an object for generating our pseudorandom numbers:

	Random r = new Random();
Our loop should look something like this (where number is the value the user has asked us to generate):

        int result;
	while (result != number) {
	    result = r.nextInt(10) + 1;
	    System.out.println("next number = " + result);
	}
Notice that we have to declare the variable result outside the while loop because it appears in the while loop test. The code above has the right approach, but Java won't accept it. It generates an error message that the variable result might not be initialized. This is an example of a loop that would need priming.

Priming a loop

Initializing variables before a loop to "prime the pump" and guarantee that we enter the loop.

We want to set the variable result to something that will cause us to enter the loop, but in some sense we don't care what value we set it to as long as it gets us into the loop. We would want to be careful not to set it to the value the user wants us to generate. We are dealing with values between 1 and 10, so we could set result to a value like -1 that is clearly outside the range of numbers we are working with. We sometimes refer to this as a "dummy" value because we don't actually process it. Later in this chapter we will see a variation of the while loop that wouldn't require this kind of priming.

Below is the complete program solution.

import java.util.*; public class Pick { public static void main(String[] args) { System.out.println("This program picks random numbers from 1 to 10"); System.out.println("until a particular number comes up."); System.out.println(); Scanner console = new Scanner(System.in); Random r = new Random(); System.out.print("Pick a number between 1 and 10--> "); int number = console.nextInt(); int result = -1; int count = 0; while (result != number) { result = r.nextInt(10) + 1; System.out.println("next number = " + result); count++; } System.out.println("Your number came up after " + count + " times"); } } Depending upon the sequence of numbers returned by the Random object, it might end up picking the given number quickly, as in this sample execution:

This program picks random numbers from 1 to 10 until a particular number comes up. Pick a number between 1 and 10--> 2 next number = 7 next number = 8 next number = 2 Your number came up after 3 times or it might take a while to pick the number, as in this sample execution:

This program picks random numbers from 1 to 10 until a particular number comes up. Pick a number between 1 and 10--> 10 next number = 9 next number = 7 next number = 7 next number = 5 next number = 8 next number = 8 next number = 1 next number = 5 next number = 1 next number = 9 next number = 7 next number = 10 Your number came up after 12 times

5.3 Type boolean

George Boole was such a good logician that a type has been named for him. You use the Java type boolean to describe logical true/false relationships. Recall that boolean is one of the primitive types like int, double and char.

Without realizing it, you have already used booleans. if/else statements and while loops are controlled by expressions that specify tests. The following expression:

	number % 2 == 0
is a test for divisibility by 2. It is also a boolean expression. Boolean expressions are meant to capture the concepts of truth and falsity, so it is not surprising that the domain of type boolean has only two values--true and false. The words true and false are keywords in Java. They are the literal values of type boolean. All boolean expressions, when evaluated, will return one or the other of these literals.

To understand this better, remember what these terms mean for type int. The The literals of type int include 0, 1, 2, and so on. Because these are literals of type int, you can do things like the following:

    int number1 = 1;
    int number2 = 0;
Consider what you can do with variables of type boolean. Suppose you define variables called test1 and test2 of type boolean. These variables can only take on two possible values--true and false. You can say:

    boolean test1 = true;
    boolean test2 = false;
You can also write a statement that copies the value of one boolean variable to another, as with variables of any other type.

    test1 = test2;
You also know that the assignment statement can use expressions:

    number1 = 2 + 2;
and that the simple tests you have been using are boolean expressions. That means you can say things like the following.

    test1 = (2 + 2 == 4);
    test2 = (3 * 100 < 250);
These assignment statements say, "set this boolean variable according to the truth value returned by the following test." The first statement sets the variable test1 to true, because the test returns true. The second sets the variable test2 to false, because the second test returns false. The parentheses are not needed, but make the statements more readable.

Many beginners don't understand these assignment statements and write code like the following.

	if (x < y)
	    less = true;
	else
	    less = false;
	END;
This is a redundant statement. First, it evaluates the truth value of the test (x < y). If the test evaluates to true, it executes the if part and assigns less the value true. If the truth evaluates to false, is executes the else part and assigns less the value false. Since you are assigning less the truth value of the if/else test, you should do it directly.

	less = (first < second);
Obviously, then, the assignment statement is one of the operations you can perform on variables of type boolean.

You form complicated boolean expressions using what are known as the logical operators.

Logical Operators
Operator Meaning Example Value
&& and (conjunction) (2 == 2) && (3 < 4) true
|| or (disjunction) (1 < 2) || (2 == 3) true
! not (negation) !(2 == 2) false

The not operator ("!") reverses the truth value of its operand. If an expression evaluates to true, its negation evaluates to false and vice versa. You can express this using a truth table. The following truth table has two columns, one for a variable and one for its negation. The table shows for each value of the variable, the corresponding value of the negation.

Truth Table for Not ("!")
p !p
truefalse
falsetrue

In addition to the negation operator, there are two logical connectives you will use, and ("&&") and or ("||"). You use these connectives to tie two boolean expressions together, creating a new boolean expression. The truth table below shows that the and operator returns true only when both of its individual operands are true:

Truth Table for And ("&&")
p q p && q
truetruetrue
truefalsefalse
falsetruefalse
falsefalsefalse

The truth table below shows that the or operator returns true except when both operands are false.

Truth Table for And ("&&")
p q p || q
truetruetrue
truefalsetrue
falsetruetrue
falsefalsefalse

The Java or operator has a slightly different meaning than the English "or." In English you say, "I'll study tonight or I'll go to a movie." One or the other will be true, but not both. The or operator behaves differently. If both operands are true, the overall proposition is true.

You generally use the logical operators when what you have to say does not reduce to one test. For example, suppose you want to do something if a number is between 1 and 10. You might say:

	if (number >= 1)
	    if (number <= 10)
		doSomething();
You can say this more easily using and:

	if (number >= 1 && number <= 10)
            doSomething();
People use the words "and" and "or" all the time. Java only allows you to use them in the strict logical sense, however. So be careful not to write code like the following:

	if (x == 1 || 2 || 3)
	    doSomething();
You can only use the and and or operators to combine boolean expressions together. Otherwise, the computer will not understand what you mean. To express this using the boolean or, you have to string three different boolean expressions together.

	if (x == 1 || x == 2 || x == 3)
	    doSomething();
Now that you have seen the operators and, or, and not, you must again consider the precedence of operators. Section 2.3.3 has a table showing Java's precedence rules. The not operator appears at the top with the highest level of precedence. The other two logical operators have a fairly low precedence, lower than the arithmetic and relational operators but higher than the assignment operators. Between the two, the and operator has a higher level of precedence than the or operator. These levels of precedence answer questions that arise when evaluating expressions like the following.

        if (!first && second || third)
            doSomething();
Here, the computer evaluates the not first, the and second, and then the or.

5.3.1 Flags and Other boolean Variables

if/else statements are controlled by a boolean test. The test can be a boolean variable as well as a boolean expression. Consider, for example, the following code.

    if (number > 0)
        System.out.println("positive");
    else
        System.out.println("negative");
It could be rewritten as follows.

    boolean positive = (number > 0);
    if (positive)
        System.out.println("positive");
    else
        System.out.println("negative");
Boolean variables add to the readability of programs because they allow you to give names to tests. Consider the kind of code you would generate for an address book program. You might have some integer variables that describe certain attributes of a person: looks, to store a rough estimate of physical beauty (on a scale of 1-10); IQ, to store intelligence quotient; income, to store gross annual income; and snothers, to track intimate friends (snother is short for "significant other"). Given these variables to specify the attributes of a person, you can develop various tests of suitability. Boolean variables are useful here to give names to those tests and add greatly to the readability of the code.

    boolean cute = (looks >= 9);
    boolean smart = (IQ > 125);
    boolean rich = (income > 100000);
    boolean available = (snothers == 0);
    boolean awesome = cute && smart && rich && available;
You might find occasion to use a special kind of boolean variable called a flag. Typical use is within loops to record error conditions or to signal completion. Different flags test different conditions. The analogy is to a referee at a game that watches for a particular illegal action and throws a flag if it happens. For example, in a football game there is a special line called the line of scrimmage that player's aren't supposed cross until the ball is in play. If one of them crosses that line too early, a referee blows a whistle and throws a flag on the ground to signal what is called "off sides." Let's look at a pseudocode description of what that referee might do.

        for (each step taken by a team member)
	    if (this step puts the player over the scrimmage line)
		set offsides to true.
	    else
		set offsides to false.
        if (offsides)
            impose penalty.
This does not perform the way you want it to because offsides can be reset to false after having been set to true. This is not what we want. A team is not forgiven by stepping back to their side of the scrimmage line. Once the whistle blows and the flag is thrown, it should stay thrown. So we need pseudocode more like this:

        for (each step taken by a team member)
	    if (this step puts the player over the scrimmage line)
		set offsides to true.
        if (offsides)
            impose penalty.
There is one problem with this pseudocode. What happens if nobody goes offsides? How does the flag get a value? You need to initialize it. The simple fix is to start the flag out as false outside the loop, assuming innocence until guilt is proven. Here is the pseudocode. It shows you the basic way to use flags in programs.

        set offsides to false.
        for (each step taken by a team member)
	    if (this step puts the player over the scrimmage line)
		set offsides to true.
        if (offsides)
            impose penalty.
Let's introduce a flag into the cumulative sum code we saw in the previous chapter.

	double sum = 0;
	for (int i = 1; i <= totalNumber; i++) {
	    System.out.print("    next--> ");
	    double next = console.nextDouble();
	    sum += next;
	}
	System.out.println("Sum = " + sum);
Suppose we want to know if the sum ever goes negative. Notice that this isn't the same question of whether the sum ends up being negative. It might switch back and forth between positive and negative. This is a lot like what happens with a bank account. You might make a series of deposits and withdrawals, but the bank wants to know if you overdrew your account anywhere along the way. Using the pseudocode above, we can modify this loop to keep track of whether the sum ever goes negative and we can report it after the loop.

	double sum = 0;
	boolean negative = false;
	for (int i = 1; i <= totalNumber; i++) {
	    System.out.print("    next--> ");
	    double next = console.nextDouble();
	    sum += next;
	    if (sum < 0)
		negative = true;
	}
	System.out.println("Sum = " + sum);
	if (negative)
	    System.out.println("Sum went negative");
	else
	    System.out.println("Sum never went negative");

5.4 Other Indefinite Loops

As we have seen, the while loop tests at the "top" of the loop before it executes its controlled statement. Java has an alternative known as the do/while loop that tests at the "bottom" of the loop. It has the following syntax:

do <statement>; while (<test>); For example
	int number = 1;
	do
	    number *= 2;
	while (number <= 200);
This loop produces the same result as the corresponding while loop, doubling the variable number until it reaches 256, which is the first power of 2 greater than 200. But unlike the while loop, the do/while loop always executes its controlled statement at least once.

Recall that the while loop operates like this, testing before executing the controlled statement:

    loop
        evaluate test.
        if test returns false then exit.
        execute controlled statement.
    end of loop
The do/while loop executes like this, always executing the controlled statement at least once:

    loop
        execute controlled statement.
        evaluate test.
        if test returns false then exit.
    end of loop
There are many programming problems where the do/while is the more appropriate statement. This occurs often with interactive programs where you know you want to do something at least once. For example, you might have a loop that allows a user to play a game multiple times but you can be fairly sure that the user wants to play at least once. Or if you are playing a guessing game with the user, you will always have to obtain at least one guess.

We saw a situation like this earlier with the program that picked pseudorandom numbers between 1 and 10 until a certain number is picked. You know you have to pick at least once, so a do/while is appropriate. The while loop version required priming, which involved initializing a variable before the loop. With the do/while version, we don't need to initialize because we know the loop will execute at least once:

import java.util.*; public class Pick2 { public static void main(String[] args) { System.out.println("This program picks random numbers from 1 to 10"); System.out.println("until a particular number comes up."); System.out.println(); Scanner console = new Scanner(System.in); Random r = new Random(); System.out.print("Pick a number between 1 and 10--> "); int number = console.nextInt(); int result; int count = 0; do { result = r.nextInt(10) + 1; System.out.println("next number = " + result); count++; } while (result != number); System.out.println("Your number came up after " + count + " times"); } } Notice that, as always, we use curly braces to turn multiple statements into a block. You might be tempted to move the declaration for the variable result inside the do/while loop, but that won't work because it appears in the loop test which is outside the curly braces.

5.4.1 Break and "forever" loops

The while loop has its test at the top of the loop and the do/while has its test at the bottom of the loop. That should lead you to wonder whether it might be desirable to have the test in the middle of the loop. There is a way to accomplish this in Java, although it requires some odd looking loops.

Java has a special statement called "break" that will exit a loop. You can use it to break out of any of the loops we have seen (while, do/while, for). Loops with break statements can be difficult to understand, so the practice is generally discouraged. But there is an interesting application of break to form a loop where the test occurs in the middle. The problem is that we still need to choose one of the standard loop constructs (while, do/while, for). One common choice is to form what appears to be an infinite loop with a while loop:

while (true) { <statements> } Because the boolean literal "true" always evaluates to true, this while loop appears to execute indefinitely. But you can include a test in the middle of the loop with a break statement. This technique is useful for solving the fencepost problem. Recall that we wrote the following code to solve a fencepost problem:

    Scanner console = new Scanner(System.in);

    int sum = 0;
    System.out.print("next integer (-1 to quit)? ");
    int number = console.nextInt();
    while (number != -1) {
        sum += number;
        System.out.print("next integer (-1 to quit)? ");
        number = console.nextInt();
    }
    System.out.println("sum = " + sum);
The code to prompt and read appears twice, once before the loop executes and once at the bottom of the loop. Using a while loop with a break, we can eliminate this redundancy:

    Scanner console = new Scanner(System.in);

    int sum = 0;
    while (true) {
        System.out.print("next integer (-1 to quit)? ");
        int number = console.nextInt();
        if (number == -1)
            break;
        sum += number;
    }
    System.out.println("sum = " + sum);
Keep in mind that the while loop test is not the real test for this loop. The real test appears in the middle when we see if number is equal to -1, in which case we break. By having the test in the middle, we have a simpler solution to the "loop and a half" problem. We exit the loop on the final iteration after doing the "half" that we want.

Another form of this loop is to use a for loop that has none of the usual initialization, test and update code. The for loop still needs the parentheses and semicolons, but the rest can be empty. This leads to the following rather odd looking code:

    Scanner console = new Scanner(System.in);

    int sum = 0;
    for (;;) {
        System.out.print("next integer (-1 to quit)? ");
        int number = console.nextInt();
        if (number == -1)
            break;
        sum += number;
    }
    System.out.println("sum = " + sum);
The "for (;;)" has the same effect as the "while (true)" loop. In other words, it would normally be an infinite loop. It's okay in this case because the true loop test appears in the middle of the loop with a break.

People tend to either love or hate this version of the for loop and for the same reason. The people who hate it say, "This looks too strange." The people who love it say, "I'm glad it looks strange because it makes it clear that the real loop test is somewhere else." Some people read the "for (;;)" as "forever" and refer to these as "forever loops."

Many advocates of structured programming argue that neither of these loops is a reasonable alternative. They argue that the break statement is like the "goto" construct that many computer scientists have argued leads to unstructured "spaghetti" code. Obviously different programmers will make up their own minds about whether they like this construct or not.

5.5 Assertions and Program Logic

Logicians concern themselves with assertions.

Assertion

A declarative sentence that is either true or false.

The following are all assertions.

	2 + 2 = 4
	The sun is larger than the earth.
	x > 45
	It was raining.
	The rain in Spain falls mainly on the plain.
The following are not assertions. The first is a question and the second is a command.

	How much do you weigh?
	Please take me home.
Some assertions are true or false depending upon context.

	x > 45			This depends on x.
	It was raining.		This depends on when and where.
You can pin down whether they are true or false by providing a context.

	when x = 13, x > 45
	On July 4, 1776 in Philadelphia, it was raining.
To write programs correctly and efficiently, you must learn to make assertions about your programs and to understand the contexts in which those assertions will be true. For example, if you are trying to obtain a nonnegative number from the user, you want the assertion "Number is nonnegative" to be true. What happens if you use a simple prompt and read?

    System.out.print("Please input a nonnegative number--> ");
    double number = console.nextDouble();
    // Is number nonnegative here?
The user can ignore your request and input a negative number anyway. In fact, users often input values that you don't expect, most often because they are confused. Given the uncertainty of user input, this particular assertion is sometimes true and sometimes false. It might be important to be certain that this assertion is true for something that appears later in the program. For example, if you are going to take the square root of that number, you must be sure it is nonnegative. Otherwise, you might end up with a bad result.

Using a loop we can guarantee that the number we get is nonnegative.

    double number;
    do {
        System.out.print("Please input a nonnegative number--> ");
        number = console.nextDouble();
    } while (number < 0.0);
    // Is number nonnegative here?
You know that number will be positive after the loop; otherwise, you would not exit the do/while loop. As long as a user gives negative values, your program stays in the do/while loop and continues to prompt for input.

This doesn't mean that the number "should be nonnegative" after the loop. It means the number "will be nonnegative." By working through the logic of the program, you can see that this is a certainty. It is an assertion of which you are sure. You could even prove it if need be. Such an assertion is called a provable assertion.

Provable assertion

An assertion that can be proven to be true at a particular point in program execution.

Provable assertions help to identify unnecessary bits of code. Consider these statements:

	int x = 0;
	if (x == 0)
            System.out.println("This is what I expect.");
	else
            System.out.println("how can that be?");
The if/else is not necessary. It tests something you know is a fact because you know how assignment statements work and you notice the assignment statement before the if/else sets the variable x to zero. Testing whether or not it's zero is like saying, "Before I proceed, I'm going to check that 2 + 2 equals 4." Because the if part of this if/else is always executed, you can prove that these lines of code always do the same thing.

	int x = 0;
        System.out.println("This is what I expect.");
This code is simpler and, therefore, better. Programs are complex enough without adding unnecessary code.

5.6 Preconditions and Postconditions

You can formally describe the workings of a method using assertions. For example, you can give a series of assertions that describe what will be true when a method is done executing. Such assertions are called postconditions of a method. For example, to describe the job of a person on an auto assembly line, you might use a postcondition like, "The bolts that secure the left front tire are on the car and tight."

Postconditions are not the whole story. Employees on an assembly line depend on each other. A line worker can't add bolts and tighten them if the left tire isn't there or if there are no bolts. You specify conditions like these by using preconditions, assertions that must be true before a task is performed. The assembly line worker might have preconditions like, "the left tire is mounted properly on the car; there are at least 8 bolts in the supply box; and a working wrench is available." You describe the task fully, then, by saying that the worker can make the postconditions true if the preconditions are true before starting.

Precondition

An assertion that must be true before a method executes to guarantee that it can perform its task.

Postcondition

An assertion that the method guarantees will be true after it finishes executing as long as the preconditions were true before it was called.

Methods, like workers on an assembly line, need to work together, each solving its portion of the task, in order to solve the overall task. The preconditions and postconditions describe the dependencies between methods. To understand this better, consider this nonprogramming example with the following methods and their conditions.

        makeBatter
                pre : bowl is clean.
                post: bowl has batter in it; bowl is dirty.
        bakeCake
                pre : bowl has batter in it; pan is clean.
                post: cake is baked; pan is dirty.
        washDishes
                pre : none.
                post: bowl and pan are clean.
When you call these methods, you must fit them together so the preconditions are always satisfied before a method executes. For example, if you suppose that the bowl and pan are initially clean, you can make a cake as follows.

        makeBatter.
        bakeCake.
Here is a trace of its execution.

        --> bowl and pan are clean.
        makeBatter.
        --> bowl has batter in it; bowl is dirty; pan is clean.
        bakeCake.
        --> cake is baked; bowl and pan are dirty.
The preconditions are satisfied before each method is executed. However, if you want a loop to make cakes, you can't do it this way.

        for (many cakes) {
            makeBatter.
            bakeCake.
        }
The first cake is made properly, but not the second. The error occurs because the preconditions for makeBatter are not satisfied on the second execution of the loop. You need a clean bowl and pan to execute makeBatter.

        --> bowl and pan are clean.
        makeBatter.
        --> bowl has batter in it; bowl is dirty; pan is clean.
        bakeCake.
        --> cake is baked; bowl and pan are dirty.
        makeBatter.
You need to change your solution.

        for (many cakes) {
            makeBatter.
            bakeCake.
            washDishes.
        }
The execution of washDishes leaves you with a clean bowl and pan and guarantees that you satisfy the preconditions of makeBatter on the next iteration.

5.7 Programming Problems

  1. Write an interactive program that prompts for an integer and displays the same number in binary. How would you modify the program to make it display in base 3 rather than base 2?