Last
time, I introduced BlueJ,
an integrated Java environment that is used to teach object
orientation to students. BlueJ emphasizes classes and objects as
its basic units of interaction: it does not force the student to
learn Java's public static void main(String [] args)
method or worry about input/output prior to creating and
interacting with objects.
In the previous article, you also learned how to install BlueJ
and how to select an appropriate J2SE SDK for use with BlueJ.
Moving on, you toured BlueJ's GUI, where you discovered that
BlueJ's main window divides into a menu bar, a project tool bar, a
class diagram, an object bench, and a message area. Finally, you
were introduced to some features, such as the object inspector and
the class diagram's project description note icon, while developing
a simple payroll application.
This article delves deeper into BlueJ. It begins by exploring
BlueJ's debugging, documentation, executable JAR files, code pad,
and unit testing features. The article next focuses on
configuration, where you learn how to change configuration options
from within BlueJ and outside of BlueJ. Continuing, the article
shows you how to extend BlueJ and identifies several useful
extensions. The article concludes by addressing some concerns about
BlueJ.
Note: This series is based on BlueJ version 2.0.4 and J2SE 5.0
on the Windows 98 SE platform.
More BlueJ Features
BlueJ provides quite a few features beyond those features that
were explored in the previous article. For brevity, this section
focuses only on BlueJ's debugging, documentation, executable JAR
files, code pad, and unit testing features. Subsequent sections
look at configuration and extension features. For applet-oriented
and other features not explored in this series, I recommend
studying the BlueJ tutorial: select the BlueJ Tutorial menu item
from the Help menu.
Debugger
First-year students face many challenges while learning how to
use an IDE. After struggling to learn the IDE's editor, the
compiler, and project execution, students often don't have
sufficient time to also learn about the debugger (which can be
quite complicated). And yet, learning how to use the debugger is
important: debugging skills motivate students to fix coding
mistakes right from the start. Recognizing time constraints,
BlueJ's debugger isn't complicated. Its functionality is organized
around setting breakpoints, stepping through the code, and
inspecting variables.
Before we investigate the debugger, we need something to debug.
The previous article's payroll application is not appropriate,
because it works correctly. Instead, consider an application that
converts integer values to strings of words (perhaps for
check-printing purposes). That application's source code appears
below.
The source code above isn't commented, for brevity. The source
code also isn't commented because it contains a bug--when
confronted with 327, the application outputs three hundred
and thirty-seven instead of three hundred and
twenty-seven--and I hope to make it harder to find that
bug without using the debugger.
Start BlueJ and create a new project called
"DigitsToWords." Introduce a DigitsToWords
class and, via BlueJ's editor, replace the default source code with
the source code above.
Compile the project and let's go bug hunting. The first thing we
must do is establish a breakpoint at an appropriate location in the
source code, so that the debugger activates when execution reaches
the breakpoint. Accomplish that task by starting the editor and
clicking the mouse in the breakpoint area to the left of the line
containing System.out.println (convertDigitsToWords
(327));. In response, BlueJ displays a small icon in the
breakpoint area, as Figure 1 reveals.
Figure 1. BlueJ identifies breakpoints with small stop-sign
icons
After closing the editor, right-click the DigitsToWords class
icon and select void main(String []args) from the
pop-up menu. Respond to the "Method Call" dialog box by clicking the
OK button. After a few moments, the application starts running.
Execution continues until the breakpointed line is reached. When
that happens, the editor window opens with the breakpointed line
highlighted. Furthermore, the debugger window opens. Figure 2
illustrates both windows.
Figure 2. The small arrow icon in the editor window's breakpoint
area identifies the line that is about to be executed. Use the
debugger window to control this execution.
The debugger window divides into a menu bar, a threads window, a
call sequence window, a static variables window, an instance
variables window, a local variables window, and a command area:
The menu bar presents a single Options menu with menu
items for hiding system threads (so that they don't appear in the
threads window) and for closing the debugger window.
The threads window identifies an execution's threads
(which might or might not include system threads) plus their
statuses (such as at breakpoint, stopped, or running).
The call sequence window identifies nested method calls,
with the name of the most recently called method at the top of this
window.
The static variables window identifies static variables
and their values.
The instance variables window identifies instance
variables and their values.
The local variables window identifies variables local to
the current method and their values. Figure 2 reveals a single
local variable at this point in the execution: args.
Because that variable has reference type (as indicated by
<object reference>), you must double-click the
variable to activate the Object Inspector dialog box and view the
variable's value. Of course, there is no value for
args--unless you passed something to this
application via the Method Call dialog box.
The command area presents buttons for interrupting a
long-running execution (Halt), executing the next line of code
without entering a method call (Step), executing the next line of
code and entering a method call (Step Into), restarting execution
and continuing normally after removing a breakpoint or continuing
interrupted execution (Continue), and terminating the entire
execution should you run into an infinite loop (Terminate).
Because Terminate can leave objects in an inconsistent state,
this button should be used only to exit infinite loops and deal
with other emergencies.
Click the Step Into button. Execution proceeds into the
convertDigitsToWords() method: if (integer <
0 || integer > 9999) is highlighted as the next line to
execute.
Click the Step button to execute the if
statement; keep clicking Step until result.append (group3
[tmp - 1]); is highlighted. At this point, the local
variables window reveals 2 as the value of tmp.
Furthermore, group3 [2 - 1] references
"thirty" instead of "twenty". It seems we
have found our bug: instead of subtracting 1 from tmp,
we should be subtracting 2.