Extended Loop Patching Example:
In the examples below, various deliberate errors are made initially to illustrate the process of programming.
The examples are shown just as simple loops inside a main function, but at the end the task of the loop is reformulated to take the form of a object-oriented example.
Consider the following problem statement:
You are to write a Java program that will read integer exam scores one at a time until a -1 signals the end of the input. The first try at a program is the following (which uses the GetNext class for user input):
NOTE: INCORRECT PROGRAM
// ExamScores.java: read scores and calculate average
public class ExamScores {
public static void main (String[] args) {
int score;
int sum = 0;
int count = 0;
double average;
while (score != -1) {
score = GetNext.getNextInt();
count++;
sum = sum + score;
}
System.out.println("count: " + count + ", sum: " + sum);
average = (double)sum/(double)count;
System.out.println("average: " + average);
} // end of main
}
When the program is run with the given input, the result is:
count: 4, sum: 269 average: 67.25Well, this isn't right! The average is not even close! Thinking about it, we see that the program is counting the final -1 and also adding it into the sum. The result is that the count is one too big and the sum is one too small. So we just initialize count to -1 and sum to 1 to compensate. (This is a much worse pair of patches.) This gives the following, with the corresponding run:
NOTE: FLAWED PROGRAM (flaws partly marked in red)
// ExamScores.java: read scores and calculate average
public class ExamScores {
public static void main (String[] args) {
int score = 0;
int sum = 1;
int count = -1;
double average;
while (score != -1) {
score = GetNext.getNextInt();
count++;
sum = sum + score;
}
System.out.println("count: " + count + ", sum: " + sum);
average = (double)sum/(double)count;
System.out.println("average: " + average);
} // end of main
}
Enter: 80 100 90 -1
Get output:
count: 3, sum: 270
average: 90.0
The next day our supervisor says that users are entering various negative numbers to terminate the input, rather than just -1, and they are getting the wrong answers. We try to insist that the users be made to use just -1, but eventually we agree to rewrite the program so that any negative number will terminate the input. Eventually, we decide to alter the final value of score so that the answer will be correct. Just after the while loop, we add the statement:
which should compensate for the extra negative score added in. When we compile and run this, the result is even further off, so we try:
We also waste a run till we realize that the while condition needs to be while (score >= 0). The final version of the program now looks like:
NOTE: TERRIBLY FLAWED PROGRAM (flaws partly marked in red)
// ExamScores.java: read scores and calculate average
public class ExamScores {
public static void main (String[] args) {
int score = 0;
int sum = 1;
int count = -1;
double average;
while (score >= 0) {
score = GetNext.getNextInt();
count++;
sum = sum + score;
}
sum = sum - score - 1;
System.out.println("count: " + count + ", sum: " + sum);
average = (double)sum/(double)count;
System.out.println("average: " + average);
} // end of main
}
Enter: 80 100 90 -47
Get output:
count: 3, sum: 270
average: 90.0
Notice that in the statement sum = sum - score - 1;, the final - 1 is only there because of the earlier patch to initialize sum to 1.
FIRST GOOD VERSION OF PROGRAM (Uses infinite loop. Changes partly commented in red.)
// ExamScores.java: read scores and calculate average
public class ExamScores {
public static void main (String[] args) {
int score;
int sum = 0;
int count = 0;
double average;
for (;;) { // infinte loop, must terminate inside
score = GetNext.getNextInt();
// terminate loop right after reading the negative score
// without counting the negative number as a score or adding it in
if (score < 0) break;
count++;
sum = sum + score;
}
System.out.println("count: " + count + ", sum: " + sum);
average = (double)sum/(double)count;
System.out.println("average: " + average);
} // end of main
}
// ExamScores.java: read scores and calculate average
public class ExamScores {
public static void main (String[] args) {
int score;
int sum = 0;
int count = 0;
double average;
// use a "priming" read just before the loop
score = GetNext.getNextInt();
while (score >= 0) { // this will terminate loop when negative number read
count++;
sum = sum + score;
score = GetNext.getNextInt();
}
System.out.println("count: " + count + ", sum: " + sum);
average = (double)sum/(double)count;
System.out.println("average: " + average);
} // end of main
}
// ExamScores.java: read scores and calculate average
public class ExamScores {
public static void main (String[] args) {
int score;
int sum = 0;
int count = 0;
double average;
// use tricky assignment and test inside while condition
// this will terminate loop when negative number read
while ( (score = GetNext.getNextInt()) > 0) {
count++;
sum = sum + score;
}
System.out.println("count: " + count + ", sum: " + sum);
average = (double)sum/(double)count;
System.out.println("average: " + average);
} // end of main
}
package looppkg;
public class ExamScores {
private int score;
private int sum;
private int count;
public ExamScores() {
sum = 0;
count = 0;
}
public double calculateAverage() {
double average;
// this will terminate loop when negative number read
while ( (score = GetNext.getNextInt()) > 0) {
count++;
sum = sum + score;
}
System.out.println("count: " + count + ", sum: " + sum);
average = (double) sum / (double) count;
return average;
}
}
package looppkg;
public class ExamScoresMain {
public static void main(String[] args) {
ExamScores examScores = new ExamScores();
double average = examScores.calculateAverage();
System.out.println("Average: " + average);
}
}
package looppkg;
import java.io.*;
public class GetNext {
// in: reader for reading input data
private static Reader in = new InputStreamReader(System.in);
// ch: holds the next character read
private static char ch;
public static char getNextChar() {
try {
ch = (char)in.read();
}
catch (Exception exception)
{
System.out.println("Error reading character");
ch = ' ';
}
return ch;
}
public static int getNextInt() {
int num; // the number to convert
int sign = 1; // gives sign of answer
ch = getNextChar();
// skip over initial blanks and newlines
while (ch == ' ' || ch == '\n')
ch = getNextChar();
// check for + or - sign
if (ch == '+') ch = getNextChar();
if (ch == '-') {
sign = -1;
ch = getNextChar();
}
// read digits, construct input integer;
// (same as the method "Integer.parseInt()" )
num = 0;
while (Character.isDigit(ch)) {
num = num*10 + (ch - '0');
ch = getNextChar();
}
return sign * num;
}
}