8.6 Avoiding Errors And Debugging

Avoiding Errors

  1. By far the most common error in using arrays is allowing an index to wander out of its defined range. Although this happens to everybody sooner or later, you can reduce the chance of it happening to you by (almost) always using for statements to process arrays. In setting up such statements, use the array's length to control the loop. For example, if processing the elements of an array called list, write
    for (int i = 0; i < list.length; i++) ...
  2. Even if an operation on an array has some conditional aspect, it is still usually best to use a for statement rather than a while or a do. As an example, suppose we have an array called list and we want to set the variable negativeIndex to the index of the first negative value in list (or -1 ifthere are no negative values in the array), we could write
     
       int negativeIndex = -1;
       boolean noNegative = true;
       for (int i = 0; i < list.length && noNegative; i++)
          if (list[i] < 0)
          {
             negativeIndex = i;
             noNegative = false;
          }
  3. One sure way to avoid errors with arrays is not to use them. Although this is often an unrealistic choice, there are many problems for which a solution without arrays is both possible and simpler. Before automatically creating an array, ask yourself if it is really necessary to do so. For example, if we want to read a sequence of values and determine the largest, it is not necessary to use an array because we never need all the values at once.

Debugging

  1. In debugging a program that uses arrays, it is sometimes a good idea to (temporarily) reduce the size of the arrays to very small values until the error can be found and eliminated.
  2. To trace the activity in an array, print both the components of the array and the associated index values. For example, to see what is occurring in an array called list, we could write
    for (int i = 0; i < list.length; i++)
       System.out.println("list[" + i + "] = " + list[i]); 
    In this way, you can see not only what the values are but where they are located.
  3. As with all objects, there are two parts to the creation of an array: declaration of a reference to the array and allocation of storage for the array itself. For example, the sequence
    int [] list;
    list = new int[10]; 
    first creates list, a reference to an int array and then creates an array of int values (all initialized to 0) with the variable list acting as a reference to the array. The two operations can be (and usually are) combined into one statement
    int [] list = new int[10] 
    but you should be clear about the two operations that are being performed by this single statement. If you forget to allocate space for the array, the compiler will catch you. For example, the fragment
    double [] list;
    list [0] = 1; 
    will cause the compiler to produce the message:
    variable list may not have been initialized
  4. This problem of forgetting to initialize arrays is very common with arrays of objects. As an example, the fragment
    Object[] list = new Object [10] ;
    System.out.println(list[O].equals(list[1]); 
    will compile without warning but will cause Java to throw a Null- PointerException when it attempts execution. The problem is that new here creates an array of null references. An attempt to use the instance method equals when list[0] is not referring to an instance of an object naturally causes Java to get upset.

Exercise 8.6

  1. The following fragment determines the largest number in list, an array of double values. Rewrite the fragment to make it clearer.
    double largest = list [0] ;
    int i = 1;
    while (i < list.length)
       if (list[i++] > largest)
          largest = list[i-1]; 
  2. Suppose that you are required to read a set of values and determine the given quantity. For which ones (if any) would you need to use an array?
    (a) the largest value(b) the median
    (c) the mean(d) the range
  3. Identify and correct the error in each declaration.

    1.  double a = new double [10] j 
    2. int[] b = new int[]; 
    3. char[] [] c = char [30] []; 
    4.  float [] [] d = new float [] [10] ; 
    5. int[] e = new {3,5,2,9,1}; 
  4. A programmer, using a square two-dimensional array of int values called table, wanted to sum the elements along the main diagonal (the diagonal whose elements are table[0][0], table[1][1], and so on). To do this the programmer wrote
    int total = 0;
    for (int i = 0; i < list.length; i++)
       for (int j = 0; j < list.length; j++)
          total += table[i] [j];  
    1. What does the fragment actually do?
    2. Write a fragment that does set total to the sum of the elements of the main diagonal.
    3. Write a fragment that sets total to the sum of the elements of the other diagonal of table.