Debugging Class Exercise
- Copy all files from Files, Debugging Exercise folder.
- Open eclipse and create a project for the WordAnalyzer program,
using WordAnalyzer and WordAnalyzerTester. A
WordAnalyzer is constructed with a String and contains methods to
analyze this word.
Using Stack Traces
- We are looking at the firstRepeatedCharacter method, which constains
a bug. The method is supposed to return the first character in the
word, such as c in success.
- Look at the code and predict the output, assuming that firstRepeatedCharacter
works correctly.
- Now run the program. Write down the output, including the correct output and
the error message.
- We see that we get some output and then an exception:
First repeated character = a
First repeated character = o
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 4
at java.base/java.lang.StringLatin1.charAt(StringLatin1.java:44)
at java.base/java.lang.String.charAt(String.java:692)
at WordAnalyzer.firstRepeatedCharacter(WordAnalyzer.java:26)
at WordAnalyzerTester.test(WordAnalyzerTester.java:14)
at WordAnalyzerTester.main(WordAnalyzerTester.java:7)
- When an exception occurs which is not handled, we get a stack trace,
as seen above.
The stack trace shows the statement which threw the exception, then the statement
that called it, and back through all of the calls to the original call in main.
Looking at this stack trace we can see that the exception occurred in the
Java api method java.lang.StringLatin1.charAt, which was called by
java.lang.String.charAt. Although it's tempting to think the problem is in one
of the Java functions, in fact you can be 99.99% certain that the bug is in
your code, and that you called charAt with invalid parameters. The stack trace
shows that the call at line 26 of WordAnalyzer led to the exception. What
is the code at line 26? Write down the statement.
- There are two different exceptions that can be thrown by this
statement. Write them down.
- Which of these exceptions actually occurred? Write it down.
- Knowing this, determine what caused the exception. Modify the code
and run it again. Copy down the output.
Using a Debugger
Exceptions are very helpful when your program crashes. But many errors don't
cause exceptions, they just cause your program to produce incorrect output.
One way to find this type of error is to add print statements, to show what
statements are being executed and to show the values of your variables. This
takes a lot of time: you have to add the print statements, add more, comment
them out, take them out, and then maybe put new ones in to find the next bug.
An easier way is to use a debugger. Almost all IDEs -- eclipse, NetBeans, BlueJ,
etc. -- have a built in debugger, a tool that lets you step through the
statements of your code as it executes, see which statements execute,
and look at the values of your
variables. This is why you should no longer use textpad. It's fine for small
programs but now that you are working on larger programs you will need a
debugger. Debuggers have many capabilities, but you only need to know how
to do a few things.
- Breakpoints: When you set a breakpoint at a particular statement
and run the program, execution will pause when it reaches that statement.
- Single step: After execution pauses at a breakpoint, you can execute
one statement at a time and trace the progress of your program.
- Inspect variables: At any time while debugging you can see the
values of all variables visible in the current function.
Debugging WordAnalyzer
We know from the output that the first two calls of test worked, so we would
like to investigate the third call. To set a breakpoint at the third call,
double click to the left of the line number at the beginning of the statement.
A blue dot will appear if you the breakpoint is set.
Debug the program: either choose debug from the Run menu, or click on the
debug button, which looks like a bug and is to the left of the run button.
Eclipse may ask whether you want to shift to the debug perspective; if
so, click on yes.
Eclipse has different perspectives, which determine the windows visible
within eclipse. Normally you are in the java perspective, where you see the package
explorer on the left, the edit window in the middle, and the execution window on
the bottom. When you debug, you shift to the debug perspective. In this
perspective you have the debug window on the top left, where you see the stack
of active function calls, the variable window on the top right, where you see
the values of the variables in the currently executing function, and the
code window in the middle, where you follow the execution through your statements.
At the bottom is the output window. At the right end of the eclipse toolbar are
the buttons that let you shift between the java perspective (which has a J)
and the debug perspective (which looks like a bug). Use these buttons to shift
back and forth, but stop in the debug perspective.
Your program will stop at the breakpoint, which is the call to test. When
stopping at a statement, the debugger always stops before executing
the statement. Once the program stops, you can look at variables or step through
your code.
Stepping Through Your Code
Stepping through your code means that you execure one statement at a
time. This allows you to see where the execution There are several options for
how you want to step. Once you are debugging, and you stop at a breakpoint,
these are the stepping options you will find on the Run menu. Each also has
a keyboard shortcut, as shown below.
- step into (F5): Step into will execute the current statement and
stop at the next statement. If the current statement is a function call
step into will stop at the first statement inside the called function.
This includes calls to Java API methods like System.out.println, which you
don't want to step through.
- step over (F6): Step over will execute the current statement and
stop at the next statement. If the current statement is a function call
step over will execute the function and stop at the statement after
the function call. You will use this to skip over functions that
you don't want to step through statement by statement,
including Java API methods.
- step return (F7): Step return will complete execution of the current
function, return to the caller, and stop at the statement after the function
call. You will use this to complete the execution of a function that you
know is working correctly, and continue to debug in the calling function.
- resume (F8): Resume executes your code at normal speed, starting
from the current statement and stopping at the next breakpoint, or at the
end of the program if there are no more breakpoints in the execution path.
- terminate (ctrl F2): Terminate stops execution if you don't want to
run the program to completion. You can also click on the red square on the
toolbar or on the top right of the console window.
Practice It
- Create a project for the WordAnalyzer program,
using WordAnalyzer and WordAnalyzerTester3. This is the same WordAnalyzer
and a different main method which tests the countRepeatedCharacters
method. This method counts the number of substrings that consist
of a character which is repeated. For example, the word
"mississippiii" has 4 repeated character substrings: "ss", "ss",
"pp", and "iii".
- Run the program and check the output. Write down the error you see.
- Since the program runs correctly on the first two Strings, we would like
to examine the third call and see what the code is doing. By paying
close attention to the code and variables, and thinking about what is
happening, we should be able to see what is wrong. Therefore, we
want to set a breakpoint at the third call to the test method.
- Now run the program, and it stops at the third call to test. Remember
that when it stops, it has not yet executed that statement.
- We want to watch the execution of text and countRepeatedCharacters,
so choose step into from the Run menu, or press F5. Now you are inside
the test method.
- The first line of test is the declaration and creation of the
WordAnalyzer. If we use step into again, we will be inside the constructor.
This is not of interest, so we choose step over from the Run menu, or
press F6.
- Now we are at the call to countRepeatedCharacters, which contains the
bug. We use choose step into from the Run menu, or press F5 to get into
the method.
- We are at the first line of countRepeatedCharacters, which is
int c = 0;. Step over to get to the for statement. To see the
values of variables, you can look at the variable window on the upper
right. In this window you may need to click on arrow (> symbol) to the
right of an object to see the fields of the object. The window contains
this which is the invoking object. In our case, this
is the WordAnalyzer object containing the String "aabbcdaaaabb". You
can also see the values of your variables if you hover over the variables
in the code window. Use both methods to see the values of word, i, and c.
Write down the value of word.
- Use step over to watch the loop execute. What happens to the values of
i and c? What would
happen if you used step into instead?
- The value of c changes 3 times. What are the values for i at each
increase in c? Write these values down.
- Choose resume from the Run menu, or press F8. What happens?
Debug the Program
The countRepeatedCharacters method looks for character sequences of the form xyy,
that is, a character followed by the same character and preceded by a different one.
That is the start of a group. Note that there are two conditions. The condition
if (word.charAt(i) == word.charAt(i + 1))
tests for yy, that is, a character that is followed by another one just like it.
But if we have a sequence yyyy, we only want it to count once. That's why we want to
make sure that the preceding character is different:
if (word.charAt(i - 1) != word.charAt(i))
This logic works almost perfectly: it finds three group starts:
aabbcdaaaabb. Why doesn't the method find the start of
the first ("aa") group? Can you fix the bug by changing the for loop to start
at 0 instead of 1? If not, what do you need to change to fix the method?
When you want to stop debugging, and are ready to edit your code, switch back
to the Java perspective. Remember it's the button with the J, in the upper right corner
of eclipse, at the right
end of the toolbar.
Fix the bug and run the program again. When it reaches the breakpoint, choose
resume to continue execution.
Email Me |
Office Hours |
My Home Page |
Department Home |
MCC Home Page
This exercise is taken from an exercise by Cay S. Horstmann and
Kathleen O'Brien and is licensed under a
https://creativecommons.org/licenses/by-sa/4.0/