The simplest way to check for logic errors is to examine the values of the variables in our program as the program executes, and verify that they are what they are supposed to be. emacs and xemacs provide a simple way to check variable values, using a tool named jdb (which stands for Java debugger).
Jdb allows you to run another program statement-by-statement, and examine the values of variables (or expressions) as the program runs.
To use jdb, make sure that your xemacs window has two buffers showing, one of which should contain your source program TaxTotals.java. (If you only have one buffer showing, use the xemacs C-x 2 command to split your buffer in two.)
To run jdb in the non-source-code buffer, click in that buffer and type the editor command M-x gdb. In the mini-buffer at the bottom of the window, xemacs will ask
Debug command: gdb
Since we want to debug Payroll using jdb change it to:
Debug command: jdb TaxTotals
and hit Return. Xemacs will then replace your non-source-code buffer with one named *jdb-TaxTotals* in which you can enter debugging commands. You can move the cursor back and forth between the two buffers using the keyboard C-x o command, or by clicking the mouse. The final line of the *jdb-TaxTotals* is the jdb prompt:
jdb uses a command-line environment, in which you interact through entering commands.
To run your program, you can enter the jdb run command:
Your program will then execute from start to finish within jdb. This is not what we want -- we'd rather be able to execute our program one line at a time so that we can inspect the values of variables used on that line.
To accomplish this, we must set a break point, which is sort of like placing a "stop sign" at a statement so that execution will halt when it reaches that point. Position the cursor in TaxTotals.java on the line containing the output statement for step 1 of our algorithm. Then enter the editor command C-x SPC (where SPC is the spacebar). A message like the following should appear in the *jdd-TaxTotals* buffer:
Breakpoint 1 at 0x22a: file TaxTotals.java line 16
Now that we have a "stop sign" in place, we can run TaxTotals in a controlled manner, so enter the jdb run command again.
After an introductory message, jdb will tell you that it is stopping at breakpoint 1, and then re-display its prompt. If you look in the TaxTotals.java buffer, you will notice that the line where we set the breakpoint is highlighted, with an "arrow" (=>) to its left. Under xemacs and jdb this "arrow" will always point to the statement that is to be executed next.
Now, we can use jdb commands to execute each statement in turn. For example, enter the jdb next command:
and you should see the "arrow" advance to the next executable statement. Since the statement we just executed was an output statement, jdb performs that statement, and then redisplays the jdb prompt:
This program computes total costs interactively. To begin, enter the number of items: (jdb)
The presence of the jdb prompt tells us that jdb is ready for another command, not the number of items. If you enter the jdb next command again, the next statement is an input statement which causes jdb to suspend, waiting for you to type a value. Note that the jdb prompt does NOT appear, because it is waiting for you to enter the number of items, not a jdb command. Enter 3, after which the prompt should reappear, indicating that jdb is ready for another command.
This program computes total costs interactively. To begin, enter the number of items: (jdb) 3 (jdb)
Whenever the jdb prompt is displayed, you can examine the value of an object (provided the definition of that object has been executed). For example, we can check the value of numberOfItems by by entering the jdb print command:
(jdb) print numberOfItems
If you entered 3 as the number of items, jdb will respond by displaying:
$1 = 3
where the 3 indicates the value being printed. (Ignore the $1 for now.)
The jdb print command thus allows us to inspect the value of a variable. Used in conjunction with the jdb next command, we can execute a statement and then see how that statement affected the value of a variable. You can thus use the debugger to display the current value of a variable or expression at any point in your program (following its declaration).
Using the jdb next command, continue executing the program one line at a time, entering an item, and its cost and tax rate following the execution of each input statement within the for loop. What happens when you enter the jdb next command at the end of the loop?
Continue using the jdb next command to run the program, watching the movement of the "arrow" as it runs. This should help you understand the behavior of the Java for loop.
Using the jdb run command, re-run your program. Execution will again stop at your breakpoint. Using the jdb next command, execute your program a line at a time, and enter some value which is below the minimum luxury tax value for the cost and a value for rate. Then continue using the jdb next command until the "arrow" is pointing at the line containing the call to method computeTotalCost().
This time, use the jdb step commmand:
You should see execution move through the method call:
(jdb) step computeTotalCost (cost=21, rate=7.65) at Tax.java:12
and then stop at the first line within the method. Where the jdb next command executes the next statement (including any method calls it contains), the jdb step command steps into any method calls
Use Ctrl-x SPC again to set a second breakpoint here in the method. Then continue using the jdb next command, paying particular attention to the flow of control as execution moves through the method's if statement. Note how the code that computes total cost is performed, while the code that computes luxury tax is skipped.
Continue using the jdb next command until the method terminates, noting how execution transfers back to the main function in TaxTotals.java.
With execution back in the main function, type the jdb continue command:
This causes jdb to continue execution from the current line until it reaches the next breakpoint, or the end of the program.
When jdb pauses for you to enter input values, enter a value greater than the minimum luxury tax value for cost and a value for rate. Jdb will then continue execution until your second breakpoint (within method computeTotalCost()) is reached.
Using the jdb next command, trace the flow of execution through the if statement again, noting that this time, the "normal" tax computation is skipped, but the luxury tax computation is performed. This should provide a clear illustration of selective behavior.
Use the jdb print command to display the values of regularCost, luxurySurcharge, and totalCost. Note that while totalCost can be displayed anywhere in the method, regularCost and luxurySurcharge can only be displayed when execution is within block of code in which they are defined.
Whenever you want, you can quit jdb by entering its quit command:
The debugger will display a termination message and then quit. If you want, move the cursor back into the TaxTotals.java buffer and use C-x 1 to make xemacs display a single buffer.
The key points to remember are
From this exercise, you should now know the basics of using jdb, as well as have a better understanding of how if statements and for loops work.
Back to the Lab
Back to the Table of Contents
Back to the Introduction