Debugging Tips |
As your labs become more complicated and your knowledge of the syntax of Java grows, you will discover that the type of errors you spend most of your time dealing with will change. The problems caused by errors involving the rules of Java grammar will decrease and the problems caused by subtle logical difference between what you told the computer to do and what you meant to tell it will increase.
The process of removing such logical errors is called debugging. In recognition of its growing importance we want to give you four tips on how to approach it. The first two are ways to avoid complicated debugging problems in the first place, the third is a deep, guiding principle that us useful in debugging, and the last is a simple but very handy practical technique.
Having a good understanding of the problem you are trying to solve is important to successfully debug your program. We have been encouraging you to prepare for labs by outlining each different class in the code. In addition to making your lab time more productive, this practice forces you to think clearly about the problem we are asking you to solve and to explore some of the issues and potential pitfalls that will come up when you sit down in lab to write the program.
Compile and test your code after adding small parts. Never wait until you have typed in several long methods before you start testing. This will make finding syntax errors easier, and often can give clues to potential logical errors while the problem is still reasonably small. If you do this often, you will know what you have changed recently, which helps make the next item easier.
The minute your program misfunctions, you will probably have some idea what is wrong. Suppose for example, that while you are working on a two hoop Basketball game, where you score more points for the small hoop than the large, you reach the point where you think the onMouseRelease method is correct. However, when you run the program, the score is not changed in the right way for baskets.
You might attack the problem by carefully rereading the code you have written. This is a good idea, but it is not always effective. When we write incorrect code, the error often springs from a basic misunderstanding of how our instructions will be interpreted. When we reread them, we may stick with our misunderstanding and conclude that they should work as we had intended. In order to escape our misunderstandings, we have to uncover irrefutable proof that some small section of our code is just not doing what we expected. Then, we will have to admit that something about our understanding was wrong.
The trick is to find the small section of code that will force one to recognize the mistake quickly.
In the case of the Basketball example, there are several sorts of mistakes that could cause the problem.
This is too many possibilities. As long as there are so many possibilities, the debugger will tend, while looking at the code related to one possibility, to overlook the error and assume on of the other possibilities must be at fault. Narrowing things down to a single possibility is generally the best way to force oneself to admit a misunderstanding.
This brings us to the simple technique...
Consider the BasketBall problem again. How can we narrow the search for the error down from several possibilities to just one? The answer is to try to rule out one possibility at a time.
In this example, the easiest possibility to eliminate is the third -- wrong value is being added to score when the ball goes through the big hoop. How can we tell if this is the case? One approach is to add another line to our program which a) will produce some visible output, and b) will be executed exactly when the "if" is executed. Item (b) can usually be accomplished by putting the two lines right next to one another in the program.
Producing visible output isn't too hard either. We could construct a FilledRect or a Text. An even easier thing to do, however is to simply ask Java to print a line of text. Java has a separate window from the "canvas" in which such text appears. Each line displayed is just added to the bottom of the window. You don't have to specify a Location or a canvas.
The syntax of the command used to display such text is like the following:
System.out.println("Print this line of text");
To make this concrete, consider the following (very incorrect) attempt to write the mouse release code.
public void onMouseRelease(Location point) { if (ball.contains(lastMouse)); if (bigHoop.contains(point)); score = score + 2; if (smallHoop.contains(point)); score = score + 4; if (!smallHoop.contains(point) || !bigHoop.contains(point)); score = score - 1; display.setText("Your score is " + score); ball.moveTo(BALLX, BALLY); }
To begin to track down the problem with this program, we could add a simple "println" to the if that is supposed to handle the case when the ball goes through the big hoop:
if (bigHoop.contains(point)); System.out.println("Went In Big Hoop"); score = score + 2;
and then run the program and drag the ball to the big hoop to see what happens.
If you do this, you will discover that a new window appears on the screen containing the message "Went In Big Hoop". This is proof that the program did get to the score = score + 2 instruction as desired. Now, we get to work on eliminating other possibilities.
For example, the value of score might be changed in other places in the method by mistake. We can investigate this option by changing the println to:
System.out.println("Score in Big Hoop test is " + score);
Now, the message displayed will include the value of score, and we can put similar messages in other places to narrow down where score is being modified.
Be prepared to use this trick while working on upcoming labs. It can be quite helpful.
Debugging Tips |