A Java Class with Arrays and Control Statements

This web page describes a variation of the GradeBook.java class in Chapter 7 (Figure 7.14) and the corresponding main method in GradeBookTest.java (Figure 7.15). The following Eclipse project file contains this program in the gradebook1 package. This example includes arrays, if statements, for loops, and while loops.

Arrays

An int array named foo can be declared by:

int[] foo;
and an array can be assigned to it by an array initializer:
foo = {2, 3, 5, 7};  // length 4
by creating a new array:
foo = new int[13];   // length 13, initial values all 0
or by assigning another array to the variable:
int[] bar;
...
foo = bar;           // bar and foo refer to same array
You can use any primitive type or reference type instead of int. The length of foo can be obtained using foo.length, e.g.:
System.out.printf("The length of foo is %d.\n", foo.length);

Just as in C, an array element can be accessed or modified using the notation:

array[index]
For example:
int[] foo = new int[13];
foo[0] = 1;
for (int i = 1; i < foo.length; i++) {
  foo[i] = 2 * foo[i-1];
}
// foo is now 1, 2, 4, 8, ..., 4096
One advantage of Java is that an index that is out of bounds will result in a runtime error. The tradeoff is the extra processing required for bounds checking.

The Arrays class has several useful static methods for handling arrays, especially for copying (Arrays.copyOf), sorting (Arrays.sort) and printing (Arrays.toString).

The Main Method in GradeBookTest.java

The statements in the main method of GradeBookTest.java in the gradebook1 package will be described before going on to the implementation of the GradeBook class. The main method can be divided into three parts corresponding to the three GradeBook variables: myGradeBook, gradeBook1 and gradeBook2.

The code for myGradeBook creates an array with an array initializer, constructs a GradeBook object with a course name and the array, stores the GradeBook object in myGradeBook, and then calls the displayMessage and processGrades methods of myGradeBook.

The first statement for gradeBook1 constructs a GradeBook object with just a course name and stores the GradeBook object in gradeBook1. The next four statements do the work of reading values from standard input (assuming the user is providing input): the user is prompted, a Scanner object is created for standard input, the inputGrades method of gradeBook1 is called to read the data from the Scanner object, and the Scanner object is closed. Now that the array in gradeBook1 has been initialized, the last two statements call the displayMessage and processGrades methods of gradeBook1.

The code for gradeBook2 is similar, but the values are read from a file named grades.txt. Note where this file is located in the project. In this code, the Scanner object is created for this file. Creating the Scanner object in this way requires the code to handle a FileNotFoundException in some way. The throws FileNotFoundException in the main method header passes the responsibility to whoever called the main method. Note that in this code, no user prompt is needed or desired.

The GradeBook.java Class

GradeBook.java has a field named courseName to store the name of the course. To store the grades, GradeBook.java has an additional field with name grades and type int array.

The first constructor initializes both fields. Note how the parameters are declared. Perhaps the code should make a copy of the array parameter so that the caller cannot modify the array values in grades. The second constructor only initializes courseName, which leaves grades at its initial value of null.

The setCourseName and getCourseName methods are self-explanatory. .

The processGrades method calls five methods: outputGrades, getAverage, getMinimum, getMaximum, and outBarChart. All of these methods have no parameters and do not need parameters because the object's fields are available to them, in particular the grades array.

The getMinimum method uses a for loop to process the array. Note how lowGrade is initialized and modified. Would initializing lowGrade to 0 be a mistake?

The getMaximum method uses a for-each loop to process the array. Note how highGrade is initialized and modified. Would initializing highGrade to 0 be a mistake?

The getAverage method uses a while loop to process the array. Note how total and index are initialized and modified. The return value is turned into a double using a cast. The cast converts total to a double, then before the division is performed, grades.length will be promoted to a double so that both operands are the same type. Why would removing the cast be a mistake?

The outputBarChart method uses a integer division trick to print a text representation of a bar chart. Each grade will be categorized by what range it is in, e.g., the 90s, 80s, 70s, and so on. This can be implemented by integer division by 10. Assuming that grades range from 0 to 100, then integer division by 10 will range from 0 to 10.

The frequency array keeps a count of each integer division result, e.g., frequency[7] is a count of how many grades are in the 70s. This is accomplished by creating an int array of length 11 (there are 11 values from 0 to 10) and by a for-each loop that increments the element of the frequency array that corresponds to each grade.

The next for loop prints the bar chart. For each element in the frequency array, the if statement prints the range (a grade of 100 is in a range by itself), and an inner for loop prints the appropriate number of asterisks.

The outputGrades method uses a for loop to traverse the array, printing one value per line. A more compact way to print the values of the grades array is:

System.out.println(Arrays.toString(grades));

The inputGrades method (added to the code from the book) reads ints from a Scanner object into the grades array. There are two interconnecting issues that need to be addressed: one is that the number of ints is unknown, and the other is how to detect when all the ints have been read.

The condition of the while loop is used to detect when there are no more ints to read. The hasNextInt method returns true if the next token can be read as an int, and returns false if the next token is not an int or if there is no more input, e.g., an end of file. This will result in reasonable behavior both for input from the user as well as input from a file. The user can simply enter quit, end, stop, or any non-int.

An unknown number of ints means that the length of the grades array cannot be determined in advance. The standard algorithm is to start with an array with a short length, and, as needed, double the length of the array (increasing the array length by one every loop is very inefficient). Once all the values have been read, the array is shortened to the number of ints.

The Arrays.copyOf method works by creating a new array with the specified length, copying the values from the old array to the new array, and returning the new array. The result is that many arrays are created, and only the last one is kept. Using realloc in C would have similar behavior.

The ArrayList Class

The ArrayList class is an alternative to arrays for handling an unknown number of values. An ArrayList object can be thought of as an array whose length is dynamic. An ArrayList object uses an array to store the data, but changing the array's length is automatically handled by ArrayList methods. An ArrayList version of the inputGrades method would look like:

public void inputGrades(Scanner in) {
    // Integer?  What is this Integer?
    ArrayList<Integer> gradeList = new ArrayList<Integer>();

    // Read grades and add them to gradeList.  Much cleaner.
    while (in.hasNextInt()) {
        int grade = in.nextInt();
        gradeList.add(grade);
    }

    // Copy gradeList to the grades array.
    grades = new int[gradeList.size()];
    for (int index = 0; index < gradeList.size(); index++) {
        grades[index] = gradeList.get(index);
    }
}

The add method adds a value to an ArrayList. The size method returns the number of values in the ArrayList. The get method returns the element at that index.

There are a few Java peculiarities in this sample code.

Additional Code

Additional code from Chapter 7 are included in this project. The gradebook2 package include the versions of GradeBook.java and GradeBookTest.java that operates on a 2D array of grades. The arrays package contains a demonstration of several static methods from the Arrays class. The arraylist package contains a demonstration of using ArrayLists.