Sum, Average, and Max: Examples of Loops in Java

Here is a method that, given a Scanner object (assumed to be connected to an input source that supplies a sequence of real numbers), calculates their sum:


public static double sumOf(Scanner input)
{
   double sumSoFar = 0.0; 
   // loop invariant: 
   //    sumSoFar == sum of numbers read from input source "so far"
   while (input.hasNext()) {
      // read next number and "absorb" it into the sum
      sumSoFar = sumSoFar + input.nextDouble();
   }
   return sumSoFar;
} 

Digression: To avoid a few keystrokes, some Java programmers would have used the shortcut addition operator (see Section 2.3.8 in Anderson & Franceschi) in writing the assignment to sumSoFar in the loop body:

sumSoFar += input.nextDouble();

Some people (including your instructor) frown upon the use of this operator (and the other shortcut operators), because they detract from a program's readability. End of digression.

Suppose that we wished to compute the average (i.e., arithmetic mean), rather than the sum, of the numbers accessible via some Scanner object. Not surprisingly, a method for accomplishing this task looks very much like the one above. It simply has to do a little extra work, as it is necessary to count how many numbers were read from the input source and, at the end, to divide that count into the sum of those numbers:


public static double averageOf(Scanner input)
{
   int counter = 0;
   double sumSoFar = 0.0; 
   // loop invariant: 
   //    counter == # of numbers read from input source "so far"
   //    sumSoFar == sum of numbers read from input source "so far"
   while (input.hasNext()) {
      // read next number and "absorb" it into the sum
      sumSoFar = sumSoFar + input.nextDouble();
      counter = counter + 1;
   }
   return sumSoFar / counter;
} 

What if our goal was to compute the maximum (i.e., largest) among the numbers, rather than the average. The solution is quite similar to the above examples. Rather than using a variable to store the sum of the numbers read so far, however, we use the variable maxSoFar to store the maximum of the numbers read so far. (As it is problematic to initialize maxSoFar without having read at least one number, we read the first one and assign its value to maxSoFar prior to the loop.)


public static double maxOf(Scanner input)
{
   // establish the first number as the max value read so far.
   double maxSoFar = input.nextDouble(); 

   // loop invariant: 
   //    maxSoFar == maximum of numbers read from input source "so far"
   while (input.hasNext()) {
      // read in next number and adjust maxSoFar if appropriate
      double num = input.nextDouble();
      if (num > maxSoFar) {
         maxSoFar = num;
      }
   }
   return maxSoFar;
} 

With a judicious use of the max() method in the java.lang.Math class, the if statement in the loop body can be replaced by the assignment

maxSoFar = Math.max(maxSoFar, num);

For that matter, there is really no need for storing the newly-read number in the variable num, as its only purpose is to serve as an actual argument in the call to Math.max(). Instead, we can write the entire loop body as follows:

maxSoFar = Math.max(maxSoFar, input.nextDouble());

Note that both averageOf() and maxOf have as a precondition input.hasNext(). That is, both assume that the input source provides at least one number. (This is natural in that an empty sequence of numbers has neither an average nor a maximum element.) On the other hand, sumOf() has no such precondition, as the sum of the elements in an empty sequence exists and is zero, which the method computes correctly.