# Java, Java, Java: Object-Oriented Problem Solving, 2022E

## Section6.7Example: Computing Averages

Suppose you want to compute the average of your exam grades in a course. Grades, represented as real numbers, will be input from the keyboard using our KeyboardReader class. To signify the end of the list, we will use a sentinel value—9999 or $$-1$$ or some other value that won’t be confused with a legitimate grade. Because we do not know exactly how many grades will be entered, we will use a noncounting loop in this algorithm. Because there could be no grades to average, we will use a while structure so it is possible to skip the loop entirely in the case that there are no grades to average.
The algorithm should add each grade to a running total, keeping track of the number of grades entered. Thus, this algorithm requires two variables: one to keep track of the running total and the other to keep track of the count. Both should be initialized to 0. After the last grade has been entered, the total should be divided by the count to give the average. In pseudocode, the algorithm for this problem is as follows:
initialize runningTotal to 0         // Initialize
initialize count to 0
while the grade entered is not 9999 {// Sentinel test
if (count > 0)           // Guard against divide by 0
divide runningTotal by count
output the average as the result

Note that in this problem our loop variable, grade, is read before the loop test is made. This is known as a priming read. It is necessary in this case, because the loop test depends on the value that is read. Within the loop’s body, the updater reads the next value for grade. This is a standard convention for coding while structures that involve input, as this problem does. Note also that we must make sure that count is not 0 before we attempt to compute the average because dividing by 0 would cause a divide-by-zero error.
Translating the pseudocode algorithm into Java raises several issues. Suppose we store each grade that is input in a double variable named grade. The loop will terminate when grade equals 9999, so its entry condition will be (grade != 9999). Because this condition uses grade, it is crucial that the grade variable be initialized before the bound test is made. This requires a priming read. By reading the first value of grade before the loop entry condition is tested, ensures that the loop will be skipped if the user happens to enter the sentinel (9999) on the very first prompt. In addition to reading the first exam score, we must initialize the variables used for the running total and the counter. Thus, for our initialization step, we get the following code:
double runningTotal = 0;
int count = 0;
"or 9999 to indicate the end of the list >> ");

Within the body of the loop we must add the grade to the running total and increment the counter. Since these variables are not tested in the loop entry condition, they will not affect the loop control. Our loop updater in this case must read the next grade. Placing the updater statement at the end of the loop body will ensure that the loop terminates immediately after the user enters the sentinel value:
while (grade != 9999) {    // Loop test: sentinel
count++;
"or 9999 to indicate the end of the list >> ");
} // while

You can see that it is somewhat redundant to repeat the same statements needed to do the initializating and the updating of the grade variable. A better design would be to encapsulate these into a method and then call the method both before and within the loop. The method should take care of prompting the user, reading the input, converting it to double, and returning the input value. The method doesn’t require a parameter:
private double promptAndRead() {
"or 9999 to indicate the end of the list >> ");
// Confirm input
System.out.println("You input " + grade + "\n");
}

Note that we have declared this as a private method. It will be used to help us perform our task but won’t be available to other objects. Such private methods are frequently called helper methods.
This is a much more modular design. In addition to cutting down on redundancy in our code, it makes the program easier to maintain. For example, there is only one statement to change if we decide to change the prompt message. It also makes the program easier to debug. Input errors are now localized to the promptAndRead() method.
Another advantage of encapsulating the input task in a separate method is that it simplifies the task of calculating the average. This task should also be organized into a separate method:
public double inputAndAverageGrades() {
double runningTotal = 0;
int count = 0;
while (grade != 9999) {      // Loop test: sentinel
count++;
} // while
if (count > 0)      // Guard against divide-by-zero
return runningTotal / count;// Return the average
else
return 0;         // Special (error) return value
}

Note that we have declared this as a public method. This will be the method you call to calculate your course average.
Because we have decomposed the problem into its subtasks, each subtask is short and simple, making it easier to read and understand. As we saw in the checkerboard example, the use of small, clearly-focused methods is a desireable aspect of designing a program.

### Activity6.7.1.Average.

The complete Average.java application is shown in Listing 6.7.3 or at Average on repl. Try it below.
One final point about this program is to note the care taken in the design of the user interface to explain the program to the user, to prompt the user before a value is input, and to confirm the user’s input after the program has read it.