Thursday, January 13, 2011

Debugging Java Programs Without a Debugger

Summary: This module contains tips for debugging a Java program without a debugger, primarily by printing out data during the execution of the program.



Debugging is perhaps best done using a debugger such as those provided by integrated development environments. Nevertheless, many programmers debug programs by inserting print statements. This section describes some of the techniques that can be used in Java.

Printing number data and arrays

The methods System.out.print and System.out.println are predefined for primitive types as well as for strings:
int i = 1;
double d = 5.2;
System.out.print(i);
System.out.println(d);
Furthermore, automatic conversion to String type is performed by the concatenation operator +:
System.out.println("d = " + d + "and i = " + i);
The print statements can not print an entire array, so a method must be written:
public static void print(int[] a) {
  for (int i = 0; i < a.length; i++)
    System.out.print(a[i]);
  System.out.println();
}
 
public static void main(String[] args) {
  int[] a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  print(a);
}
Since the number of elements of an array can be large, it is better to write the method so that it inserts a newline after printing a fixed number of elements:
public static void print(int[] a) {
  for (int i = 0; i < a.length; i++) {
    System.out.print(a[i]);
    if (i % 8 == 7)  System.out.println();
  }
  System.out.println();
}
You can put this static method in a publicly accessible class and use it to print any integer array. Similar methods can be written for the other primitive types.

Converting objects to strings

Within the class Object, the root class for all other classes, a method toString is declared. The default implementation will not give useful information, so it is a good idea to override it in each class that you write:
class Node {
  int key;
  double value;
  public String toString() {
    return "The value at key " + key + " is " + value;
  }
}
Then, you can simply call the print statements for any object of this class and the conversion to String is done automatically:
Node node = new Node();
...
System.out.println(node);
The predefined class java.util.Arrays constains a lot of useful (static) methods for working with arrays, among them toString methods for arrays whose elements are of any primitive type:
int[] a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
System.out.println(java.util.Arrays.toString(a));
or
import java.util.Arrays;
   ...
System.out.println(Arrays.toString(a));
You will receive a predefined representation of the array (the elements are separated by commas), so if you want an alternate representation (such as printing on multiple lines) you will have to write your own print method as we did in the previous section.
An array of objects of any reference type can be printed by defing a single method since any object can be converted to Object:
public static void print(Object[] a) {
  for (int i = 0; i < a.length; i++)
    System.out.print(a[i]);
  System.out.println();
}
 
Node[] nodes = new Node[];
   ...                         // Create elements of the array
print(nodes);
or by calling the predefined method deepToString:
Node[] nodes = new Node[];
   ...                         // Create elements of the array
System.out.println(java.util.Arrays.deepToString(node));

Forcing a stack trace

Suppose that you have isolated a bug to a certain method but you do not know which call of that method was responsible. You can force the interpreter to print a trace of the call stack by inserting the line:
new Exception().printStackTrace();
within the method. It creates a new object of type Exception and then invokes the method printStackTrace. Since the exception is not thrown, the execution of the program proceeds with no interruption. A program can always be terminated by calling System.exit(n) for an integer n.

Leave the debug statements in the program

Once you have found a bug, it is tempting to delete the print statements used for debugging, but it is better not to do so because you may need them in the future. You can comment out the statements that you don't need, but a better solution is to declare a global constant and then use it to turn the print statements on and off:
public class Global {
  public static boolean DEBUG = false;
  public static void print(int[] a) {...}
  public static void print(Object[] a) {...}
}
 
  if (Global.DEBUG) Global.print(nodes);

No comments:

Post a Comment

Related Posts Plugin for WordPress, Blogger...

java

Popular java Topics