Suppose you needed to write a program that would print a string (e.g., "Howdy Bob!") to the screen some very large number of times, say a thousand. We could, of course, (although it would be terribly inefficient and cumbersome) simply type:
System.out.println("Howdy Bob!");
System.out.println("Howdy Bob!");
System.out.println("Howdy Bob!");
.
(repeat this 1000 times)
.
System.out.println("Howdy Bob!");
Clearly, this is not a pleasant solution. The situation can be worse, however.
Consider the case where we need to write a program that generates quiz problems for first graders to help them practice subtraction. We would like to give them unlimited opportunities to "guess again" if they enter a wrong answer to any given problem.
It is conceivable, however, that a child could get the answer wrong once, twice, fifty, or a thousand or more times -- but we don't know which! When it comes to writing the code to get the input, how many statements that scan for input must be included?
Fortunately, Java provides us with "looping structures" which allow us to execute a statement or group of statements over and over again, either some fixed number of times, or until some specified condition is met.
The simplest looping structure in Java is the "while-loop". Here is the syntax:
while (someBooleanCondition) { statement(s); }
The while loop will continue to repeatedly execute the statements in the block following the boolean condition as long as the the boolean condition is true. As soon as the boolean condition is false, the loop stops, and the program proceeds normally.
So for example,
int i = 1; //initialize i as 1 while (i <= 4) { //keep printing message and System.out.println(i + " Howdy Bob!"); //increasing i by one each i++; //time until i exceeds 4 } System.out.println("Loop stopped."); //let the user know the //loop stopped
will produce the following output:
1 Howdy Bob! 2 Howdy Bob! 3 Howdy Bob! 4 Howdy Bob! Loop stopped.
Frequently, the number of times a loop is executed is not predetermined. This is especially true when trying to get data either directly from the user or, as we shall see later, from external files. In these cases we will need to scan for input values until some special value is read that signifies the end of the data has been reached. This special value is called a sentinal value.
As an example, suppose you wanted to write a program that reads and calculates the sum of an unspecified number of integers the user might input. Under the assumption that the user will never be entering a zero as one of the numbers to be added, we can use this value as our sentinal value, and instruct the user to simply input a zero when he is done entering all of the values to be summed. The following code implements this idea:
int currentSum = 0; //we haven't read any numbers yet int inputNum = myScanner.nextInt(); //get first number from user while (inputNum != 0) { //as long as user didn't type zero: currentSum = currentSum + inputNum; //add the input to the current sum inputNum = myScanner.nextInt(); //and ask user for another number } System.out.println("The sum is " + currentSum); //print final sum
Sometimes, like in the last example, we know that we want the body of the loop to be executed at least once. (In the example above, we need to ask the user to enter a value at least once -- if only for him to tell us he has no numbers to add.) This is where a "do-while-loop" might be appropriate. Here is the syntax:
do { statement(s); } while (someBooleanCondition);
In this looping structure, the statement(s) in the body of the "do-while-loop" automatically get executed once, and then they continue to be executed as long as the boolean condition following the word "while" remains true. As soon as this boolean condition becomes false, the loop terminates, and the rest of the program proceeds.
So for example, the following code:
int inputNum; int currentSum = 0; do { inputNum = myScanner.nextInt(); currentSum = currentSum + inputNum; } while (inputNum != 0); System.out.println("The sum is " + currentSum);
will also add up the numbers the user enters until the user enters a zero, and then print out the final sum. However, we don't need the extra "myScanner.nextInt()" statement, since the loop body gets executed at least once.
Many times, we do know how often some statement or group of statements should be executed. Consider again the following code:
int i = 1; //initialize i as 1 while (i <= 4) { //keep printing message and System.out.println(i + " Howdy Bob!"); //increasing i by one each i++; //time until i exceeds 4 }
which produces the following output:
1 Howdy Bob! 2 Howdy Bob! 3 Howdy Bob! 4 Howdy Bob!
Notice how the variable "i" plays the role of a "counter", keeping track of how often we have done the task of printing "Howdy Bob!" to the console.
Further, notice how
Such constructions happen so frequently in Java, that we have a special loop designed for just these situation. It is known as the "for-loop". Here is the syntax:
for (initial-action; continuation-condition; action-after-each-iteration) { statement(s); }
To rewrite the code above (which prints "Howdy Bob" 4 times, just like before), using a "for-loop", we would have:
for (int i = 1; i <= 4; i++) { System.out.println(i + " Howdy Bob!"); }
Notice how much cleaner this is!
It is possible for the initial-action and the action-after-each-iteration in a for loop can be a list of zero or more comma-separated expressions. So, for example, the following is legitimate:
for (int i = 0, j = 0; (i + j < 10); i++, j++) { //do something }
Also, if the continuation-condition in a "for-loop" is omitted, it is implicitly true. In other words:
for ( ; ; ) { //do something }
IS THE SAME AS...
while (true) { //do something }
Notice, both of these loops will do the "something" an infinite number of times (This is dangerous!), unless that "something" contains a statement that let's one "break-out" of the loop.
The "for-loop" will repeatedly execute the first statement or block statement that occurs after the specification of the initial-action, continuation-condition, and action-after-each-iteration.
A common error is to put a semicolon after the aforementioned specification. For example,
int i;
for (i = 0; i < 10; i++);
{
System.out.println(i);
}
outputs only a single
10
The semicolon (shown in red) acts as a "do-nothing" statement, and "nothing" is exactly what is repeatedly executed by the "for-loop" -- instead of the println statement. The value of i is affected (hence, the output of 10), but clearly (given the suggestion the indentation makes) the outcome is not what was intended.
Remember that floating-point numbers (like doubles) are represented only approximately in the computer. You should avoid (or at least, be REALLY careful when) using floating point number in a loop's continuation-condition. Something like the following is doomed to not work like you think it should:
double sum = 0.0; for (double d = 0.0; d != 1.0; d = d + 0.01) { //problem! sum = sum + d; }
One might think that at some point d must equal 1.0, since we started at 0.0 and added 0.01 to it repeatedly.
Unfortunately, given the approximate nature of doubles' representation, d may only eventually equal something close to 1.0 (like 1.00000000000042). Consequently, the continuation-condition never fails, and the loop just keeps on chugging away until the numbers get so huge the program chokes on them.
Moral of the story: Don't use != or == to compare floating-point numbers!
If you must compare floating-point numbers, test whether or not they are "close enough". That is to say, is the distance between these two numbers "small enough" (i.e., less than some predetermined "really small" size, which we might call "EPSILON", to borrow an idea from calculus).
To say the same thing, mathematically
These two commands are normally used with an "if-statement" to break or continue the loop under some given condition.
Interestingly, one can mathematically prove that any task you want to accomplish with a program can always be accomplished with a program that doesn't use "break" or "continue" -- but their usage can greatly shorten your code!