Chapter 1. Getting Started: Compiling, Running, and Debugging

Introduction

This chapter covers some entry-level tasks that you need to know how to do before you can go on—it is said you must crawl before you can walk, and walk before you can ride a bicycle. Before you can try out anything in this book, you need to be able to compile and run your Java code, so I start there, showing several ways: the JDK way, the Ant way, and the Integrated Development Environment (IDE) way. Another issue people run into is setting CLASSPATH correctly, so that’s dealt with next. Then I’ll discuss a few details about applets, in case you are working on them. Deprecation warnings come next, as you’re likely to meet them in maintaining “old” Java code.[1] The chapter ends with some general information about conditional compilation, unit testing, assertions, and debugging.

If you’re already happy with your IDE, you may wish to skip some or all of this material. It’s here to ensure that everybody can compile and debug their programs before we move on.

1.1. Compiling and Running Java: JDK

Problem

You need to compile and run your Java program.

Solution

This is one of the few areas where your computer’s operating system impinges on Java’s portability, so let’s get it out of the way first.

JDK

Using the command-line Java Development Kit (JDK) may be the best way to keep up with the very latest improvements from Sun. This is not the fastest compiler available by any means; the compiler is written in Java and interpreted at compile time, making it a sensible bootstrapping solution, but not necessarily optimal for speed of development. Nonetheless, using Sun’s JDK, the commands are javac to compile and java to run your program (and, on Windows only, javaw to run a program without a console window). For example:

C:\javasrc>javac HelloWorld.java

C:\javasrc>java HelloWorld
Hello, World

C:\javasrc>

As you can see from the compiler’s (lack of) output, this compiler works on the Unix “no news is good news” philosophy: if a program was able to do what you asked it to, it shouldn’t bother nattering at you to say that it did so. Many people use this compiler or one of its clones.

There is an optional setting called CLASSPATH, discussed in Recipe 1.4, that controls where Java looks for classes. CLASSPATH, if set, is used by both javac and java. In older versions of Java you had to set your CLASSPATH to include “.”, even to run a simple program from the current directory; this is no longer true on Sun’s current Java implementations. It may be true on some of the clones.

Command-line alternatives

Sun’s javac compiler is the official reference implementation. But it is itself written in Java, and hence must be interpreted at runtime. Some other Java compilers are written in C/C++, so they are quite a bit faster than an interpreted Java compiler. In order to speed up my compilations, I have used Jikes, which is fast (C++), free, and available both for Windows and for Unix. It’s also easy to install and is included with the Mac OS X Developer Tools package. For Windows, Linux, and other Unix systems, you can find binaries of the current version on IBM’s Jikes web site. If you are using OpenBSD, NetBSD, or FreeBSD, you should only need to run something like:

                  cd /usr/ports/lang/jikes; sudo make install

or just download the package file and use pkg_add to get it installed. Visit http://oss.software.ibm.com/developerworks/projects/jikes/ for Jikes information and downloads.

What I really like about Jikes is that it gives much better error messages than the JDK compiler does. It alerts you to slightly misspelled names, for example. Its messages are often a bit verbose, but you can use the +E option to make it print them in a shorter format. Jikes has many other command-line options, many that are the same as the JDK compiler’s, but some that go beyond them. See Jikes’s online documentation for details.

Another alternative technology is Kaffe, a product that Transvirtual licenses but also makes available in open source form (at http://www.kaffe.org/) under the GNU Public License. Kaffe aims to be a complete JDK replacement, though it has moved rather slowly and is not quite a complete, up-to-date Java 2 clone as of this writing. Again, Kaffe is available for BSD Unix and for Linux in RPM format. Visit the Kaffe web site for the latest information on Kaffe.

Other freeware programs include Japhar, a Java runtime clone, available from http://www.hungry.com/old-hungry/products/japhar/, and the IBM Jikes Runtime from the same site as Jikes.

If you really want to get away from the mainstream, consider investigating JNODE, the Java New Operating system Development Idea, at http://www.jnode.org/. JNODE is a complete operating system written in Java, a kind of proof of concept. At this point JNODE is probably not something you would use for your main desktop—I’ve booted it only under Virtual PC on Mac OS X—but it could become that someday.

Mac OS X

The JDK is pure command-line. At the other end of the spectrum in terms of keyboard-versus-visual, we have the Apple Macintosh. Books have been written about how great the Mac user interface is, and I won’t step into that debate. Mac OS X (Release 10.x of Mac OS) is a new technology base built upon a BSD Unix base. As such, it has a regular command line (the Terminal application, hidden away under /Applications/Utilities), as well as all the traditional Mac tools. It features a full Java implementation, including two GUI packages, Sun’s Swing and Apple’s own Cocoa. JDK 1.4.2 has been released for Mac OS 10.3 as of this writing; the latest version is always available from Software Update.

Mac OS X users can use the command-line JDK tools as above or Ant (see Recipe 1.7). Compiled classes can be packaged into “clickable applications” using the Jar Packager discussed in Recipe 23.7. Alternately, Mac fans can use one of the many full IDE tools discussed in Recipe 1.3.

1.2. Editing and Compiling with a Color-Highlighting Editor

Problem

You are tired of command-line tools but not ready for an IDE.

Solution

Use a color-highlighting editor.

Discussion

It’s less than an IDE (see the next recipe), but more than a command line. What is it? It’s an editor with Java support. Tools such as TextPad (http://www.textpad.com), Visual Slick Edit, and others are low-cost windowed editors (primarily for Windows) that have some amount of Java recognition built-in and the ability to compile from within the editor. TextPad recognizes quite a number of file types, including batch files and shell scripts, C, C++, Java, JSP, JavaScript, and many others. For each of these, it uses color highlighting to show which part of the file being edited comprises keywords, comments, quoted strings, and so on. This is very useful in spotting when part of your code has been swallowed up by an unterminated /* comment or a missing quote. While this isn’t the same as the deep understanding of Java that a full IDE might possess, experience has shown that it definitely aids programmer productivity. TextPad also has a “compile Java” command and a “run external program” command. Both of these have the advantage of capturing the entire command output into a window, which may be easier to scroll than a command-line window on some platforms. On the other hand, you don’t see the command results until the program terminates, which can be most uncomfortable if your GUI application throws an exception before it puts up its main window. Despite this minor drawback, TextPad is a very useful tool. Other editors that include color highlighting include vim (an enhanced version of the Unix tool vi, available for Windows and Unix platforms from http://www.vim.org), the ever-popular Emacs editor, and many others.

And speaking of Emacs, since it is so extensible, it’s natural that people have built enhanced Java capabilities for it. One example is JDEE (Java Development Environment for Emacs), an Emacs “major mode” (jde-mode, based on c-mode) with a set of menu items such as Generate Getters/Setters. You could say that JDEE is in between using a Color-Highlighting Editor and an IDE. The URL for JDEE is http://jdee.sunsite.dk/.

Even without JDEE, Emacs features dabbrev-expand, which does class and method name completion. It is, however, based on what’s in your current edit buffers, so it doesn’t know about classes in the standard API or in external Jars. For that level of functionality, you have to turn to a full-blown IDE, such as those discussed in Recipe 1.3.

1.3. Compiling, Running, and Testing with an IDE

Problem

Several tools are too many.

Solution

Use an integrated development environment.

Discussion

Many programmers find that using a handful of separate tools—a text editor, a compiler, and a runner program, not to mention a debugger (see Recipe 1.13)—is too many. An integrated development environment (IDE[2]) incorporates all of these into a single toolset with a (hopefully consistent) graphical user interface. Many IDEs are available, ranging all the way up to fully integrated tools with their own compilers and virtual machines. Class browsers and other features of IDEs round out the purported ease-of-use feature-sets of these tools. It has been argued many times whether an IDE really makes you more productive or if you just have more fun doing the same thing. However, even the JDK maintainers at Sun admit (perhaps for the benefit of their advertisers) that an IDE is often more productive, although it hides many implementation details and tends to generate code that locks you into a particular IDE. Sun’s Java Jumpstart CD (part of Developer Essentials) said, at one time:

The JDK software comes with a minimal set of tools. Serious developers are advised to use a professional Integrated Development Environment with JDK 1.2 software. Click on one of the images below to visit external sites and learn more.

This is followed by some (presumably paid) advertising links to various commercial development suites. I do find that IDEs with “incremental compiling” features—which note and report compilation errors as you type, instead of waiting until you are finished typing—do provide somewhat increased productivity for most programmers. Beyond that, I don’t plan to debate the IDE versus the command-line process; I use both modes at different times and on different projects. I’m just going to show a few examples of using a couple of the Java-based IDEs.

One IDE that runs on both Windows and Unix platforms is NetBeans, which is a free download. Originally created by NetBeans.com, this IDE was so good that Sun bought the company and now distributes the IDE in two versions that share a lot of code: NetBeans (formerly called Forte, distributed as open source), and Sun One Studio (commercial, not open sourced). There is a plug-in API; some .nbm files will work either on the free or the Studio version while others work only on one or the other. You can download the free version and extension modules from http://www.netbeans.org; the commercial version can be had from http://www.sun.com/.

NetBeans comes with a variety of templates. In Figure 1-1, I have opted for the Swing JFrame template.

NetBeans: New From Template dialog

Figure 1-1. NetBeans: New From Template dialog

In Figure 1-2, NetBeans lets me specify a class name and package name for the new program I am building.

NetBeans: Name that class

Figure 1-2. NetBeans: Name that class

In Figure 1-3, I am building the GUI using NetBeans’ GUI builder. Select a visual component in the upper right, and click on the form where you want it. While there are several things about NetBeans that most people find quirky, I do like the fact that it defaults to using a BorderLayout ; some other IDEs default to using no layout at all, and the resulting GUIs do not resize gracefully.

NetBeans: GUI building

Figure 1-3. NetBeans: GUI building

I also like the way NetBeans handles GUI action handlers (see Recipe Recipe 14.4). You simply double-click on the GUI control you want to handle actions for, and NetBeans creates an action handler for it and puts you into the editor to type the code for the action handler. In this case, I made a deliberate typing error to show the effects; when I click the Build Project menu item, the offending line of code is highlighted in bright red, both in the source code and in the error listing from the compiler (see Figure 1-4).

NetBeans: Compilation error highlighted

Figure 1-4. NetBeans: Compilation error highlighted

Another popular cross-platform, open source IDE for Java is Eclipse, originally from IBM. Just as NetBeans is the basis of Sun Studio, so Eclipse is the basis of IBM’s WebSphere Studio Application Developer.[3] Eclipse tends to have more options than NetBeans; see for example, its New Java Class wizard shown in Figure 1-5. It also features a number of refactoring capabilities, shown in Figure 1-6.

Eclipse: New Java Class

Figure 1-5. Eclipse: New Java Class

Eclipse: Refactoring

Figure 1-6. Eclipse: Refactoring

Of these two major open source IDEs, many people like NetBeans and many like Eclipse. Many other IDEs are available for Java, especially on Windows, and almost everybody who uses one has a favorite, such as Borland JBuilder, WebGain Visual Cafe, Sun Studio, or IBM WebSphere Studio Application Developer. Most of them have a free version and/or a trial version as well as a Pro version. For up-to-date comparisons, you may want to consult the glossy magazines, since IDEs are updated relatively often.

Mac OS X includes Apple’s Developer Tools. The main IDE is Xcode in 10.3 (shown in Figure 1-7). Unlike most IDEs, Apple’s IDE does not include a GUI builder; a separate program, called Interface Builder, handles this task. Both tools can be used with a variety of programming languages, including C/C++, Objective C, and Java. While the Interface Builder is one of the nicer GUI builder tools around, at present it builds only Cocoa applications, not Swing applications. Figure 1-8 shows Xcode running a trivial application built using its default frame-based template.

Xcode (Mac OS X): Main windows

Figure 1-7. Xcode (Mac OS X): Main windows

Xcode IDE (Mac OS X): Application built and running

Figure 1-8. Xcode IDE (Mac OS X): Application built and running

How do you choose an IDE? Given that all the major IDEs can be downloaded free (Eclipse, NetBeans), “free” but without source, or at least in free trial versions, you should try a few and see which one best fits the kind of development you do. Regardless of what platform you use to develop Java, if you have a Java runtime, you should have plenty of IDEs from which to choose.

See Also

For NetBeans, see NetBeans: The Definitive Guide by Tim Boudreau, Jesse Glick, Simeon Greene, Vaughn Spurlin, and Jack J. Woehret (O’Reilly). For Eclipse, see Eclipse Cookbook by Steve Holzner (O’Reilly) or The Java Developer’s Guide to Eclipse by Sherry Shavor, Jim D’Anjou, Scott Fairbrother, Dan Kehn, John Kellerman, and Pat McCarthy (Addison Wesley). Both IDEs are extensible; if you’re interested in extending Eclipse, the book Contributing to Eclipse: Principles, Patterns, and Plugins (Addison Wesley) was written by noted OO theorists Erich Gamma (lead author of Design Patterns) and Kent Beck (author of Extreme Programming Explained).

1.4. Using CLASSPATH Effectively

Problem

You need to keep your class files in a common directory, or you’re wrestling with CLASSPATH.

Solution

Set CLASSPATH to the list of directories and/or JAR files that contain the classes you want.

Discussion

CLASSPATH is one of the more “interesting” aspects of using Java. You can store your class files in any of a number of directories, JAR files, or zip files. Just like the PATH your system uses for finding programs, the CLASSPATH is used by the Java runtime to find classes. Even when you type something as simple as java HelloWorld, the Java interpreter looks in each of the places named in your CLASSPATH until it finds a match. Let’s work through an example.

The CLASSPATH can be set as an environment variable on systems that support this (Unix, including Mac OS X, and Windows). You set it the same way you set other environment variables, such as your PATH environment variable.

Alternatively, you can specify the CLASSPATH for a given command on its command line:

               java -classpath \c:\ian\classes MyProg

Suppose your CLASSPATH were set to C:\classes;. on Windows or ~/classes:. on Unix (on the Mac, you can set the CLASSPATH with JBindery). Suppose you had just compiled a file named HelloWorld.java into HelloWorld.class and tried to run it. On Unix, if you run one of the kernel tracing tools (trace, strace, truss, ktrace), you would probably see the Java program open (or stat, or access) the following files:

  • Some file(s) in the JDK directory

  • Then ~/classes/HelloWorld.class, which it probably wouldn’t find

  • And ./HelloWorld.class, which it would find, open, and read into memory

The vague “some file(s) in the JDK directory” is release-dependent. On Sun’s JDK it can be found in the system properties:

sun.boot.class.path = C:\JDK1.4\JRE\lib\rt.jar;C:\JDK1.4\JRE\lib\i18n.jar;C:\JDK1.4\
JRE\classes

The file rt.jar is the runtime stuff; i18n.jar is the internationalization; and classes is an optional directory where you can install additional classes.

Suppose you had also installed the JAR file containing the supporting classes for programs from this book, darwinsys.jar. You might then set your CLASSPATH to C:\classes;C:\classes\darwinsys.jar;. on Windows or ~/classes:~/classes/darwinsys.jar:. on Unix. Notice that you do need to list the JAR file explicitly. Unlike a single class file, placing a JAR file into a directory listed in your CLASSPATH does not suffice to make it available.

Note that certain specialized programs (such as a web server running Java Servlets) may not use either bootpath or CLASSPATH as shown; these application servers typically provide their own ClassLoader (see Recipe 25.4 for information on class loaders).

Another useful tool in the JDK is javap, which, by default, prints the external face of a class file: its full name, its public methods and fields, and so on. If you ran a command like javap HelloWorld under kernel tracing, you would find that it opened, looked around in, and read from a file \jdk\lib\tools.jar, and then got around to looking for your HelloWorld class, as previously. Yet there is no entry for this in your CLASSPATH setting. What’s happening here is that the javap command sets its CLASSPATH internally to include the tools.jar file. If it can do this, why can’t you? You can, but not as easily as you might expect. If you try the obvious first attempt at doing a setProperty("java.class.path") to itself, plus the delimiter, plus jdk/lib/tools.jar, you won’t be able to find the JavaP class (sun.tools.java.JavaP); the CLASSPATH is set in the java.class.path at the beginning of execution, before your program starts. You can try it manually and see that it works if you set it beforehand:

C:\javasrc>java -classpath /jdk1.4/lib/tools.jar sun.tools.javap.JavaP
Usage: javap <options> <classes>...

If you need to do this in an application, you can either set it in a startup script, as we did here, or write C code to start Java, which is described in Recipe 26.6.

How can you easily store class files in a directory in your CLASSPATH? The javac command has a -d dir option, which specifies where the compiler output should go. For example, using -d to put the HelloWorld class file into my /classes directory, I just type:

               javac -d /classes HelloWorld.java

As long as this directory remains in my CLASSPATH, I can access the class file regardless of my current directory. That’s one of the key benefits of using CLASSPATH.

Managing CLASSPATH can be tricky, particularly when you alternate among several JVMs (as I do) or when you have multiple directories in which to look for JAR files. You may want to use some sort of batch file or shell script to control this. Here is part of the script that I use. It was written for the Korn shell on Unix, but similar scripts could be written in the C shell or as a DOS batch file.

# These guys must be present in my classpath...
export CLASSPATH=/home/ian/classes/darwinsys.jar:
 
# Now a for loop, testing for .jar/.zip or [ -d ... ]
OPT_JARS="$HOME/classes $HOME/classes/*.jar
    ${JAVAHOME}/jre/lib/ext/*.jar
    /usr/local/antlr-2.6.0"
 
for thing in $OPT_JARS
do
    if [ -f $thing ]; then       //must be either a file...
        CLASSPATH="$CLASSPATH:$thing"
    else if [ -d $thing ]; then       //or a directory
        CLASSPATH="$CLASSPATH:$thing"
    fi
done
CLASSPATH="$CLASSPATH:."

This builds a minimum CLASSPATH out of darwinsys.jar, then goes through a list of other files and directories to check that each is present on this system (I use this script on several machines on a network), and ends up adding a dot (.) to the end of the CLASSPATH.

1.5. Using the com.darwinsys API Classes from This Book

Problem

You want to try out my example code and/or use my utility classes.

Solution

I have built up a fairly sizeable collection of reusable classes into my own API, which I use in my own Java projects. I use example code from it throughout this book, and I use classes from it in many of the other examples. So, if you’re going to be downloading and compiling the examples individually, you should first download the file darwinsys.jar and include it in your CLASSPATH. Note that if you are going to build all of my source code (as in Recipe 1.6), you can skip this download because the top-level Ant file starts off by building the JAR file for this API.

Discussion

I have split the com.darwinsys.util package from the first edition of this book into about a dozen com.darwinsys packages, listed in Table 1-1. I have also added many new classes; these packages now include approximately 50 classes and interfaces. You can peruse the documentation online at http://javacook.darwinsys.com/docs/api.

Table 1-1. The com.darwinsys packages

Package name

Package description

com.darwinsys.database

Classes for dealing with databases in a general way

com.darwinsys.html

Classes (only one so far) for dealing with HTML

com.darwinsys.io

Classes for input and output operations, using Java’s underlying I/O classes

com.darwinsys.lang

Classes for dealing with standard features of Java

com.darwinsys.macosui

Classes for dealing with Swing GUIs slightly differently under Mac OS X

com.darwinsys.mail

Classes for dealing with e-mail, mainly a convenience class for sending mail

com.darwinsys.sql

Classes for dealing with SQL databases

com.darwinsys.swingui

Classes for helping construct and use Swing GUIs

com.darwinsys.swingui.layout

A few interesting LayoutManager implementations

com.darwinsys.util

A few miscellaneous utility classes

Many of these classes are used as examples in this book; just look for files whose first line is:

package com.darwinsys.nnn;

You’ll also find that many examples have imports from the com.darwinsys packages.

1.6. Compiling the Source Code Examples from This Book

Problem

You want to try out my examples.

Solution

Download the latest archive of the book source files, unpack it, edit build.properties, and run Ant (see Recipe 1.7) to compile the files.

Discussion

You can download the latest version of the source code for all the examples in this book from the book’s web site, http://javacook.darwinsys.com/. You can get it all as one large file containing all the source code, in a file called javacooksrc.jar, which you should unzip into an empty directory someplace convenient, wherever you like to keep source code. You should then edit the file build.properties, specifying the locations of some jar files. Editing build.properties and then running ant in this directory first creates a file called darwinsys.jar [4]containing the com.darwinsys API described in Recipe 1.5 (you will probably want to add this file to your CLASSPATH—see Recipe 1.4—or to your JDKHOME/jre/lib/ext directory). Ant goes on to build as many of the other examples as it can given the settings in build.properties, your Java runtime, and your operating system. The files are roughly organized in per-chapter directories, but there is a lot of overlap and cross-referencing. Because of this, I have prepared a cross-reference file named index-bychapter.html. A mechanically generated file called index-byname.html can be used if you know the name of the file you want (and remember that Java source files almost always have the same name as the public class they contain). The canonical index file, index.html, links to both these files.

If you have JDK 1.3 or 1.4 instead of 1.5, a few files will not compile, but the compiler prints a comment about needing 1.4 or 1.5. And the “native code” examples may not compile at all. Most everything else should compile correctly.

If you’re not using Ant, well, you should! But if you can’t, or won’t, after you’ve set your CLASSPATH, you should compile what you need. You will need the darwinsys.jar file; you should probably just download it. In some directories you can simply say javac *.java or jikes *.java. But in others, you have to set your CLASSPATH manually; if some files that you need won’t compile, you’ll have to look in the Ant file build.xml to see what jar files are needed. I no longer provide Makefiles; Ant has simply become the dominant build tool for Java developers.

There may also be times when you don’t want to download the entire archive—if you just need a bit of code in a hurry—so you can access those index files and the resulting directory, for “anyplace, anytime access” on the same web site, http://javacook.darwinsys.com/

A caveat

One of the practices of Extreme Programming is Continuous Refactoring—the ability to improve any part of the code base at any time. Don’t be surprised if the code in the online source directory is different from what appears in the book; it is a rare week that I don’t make some improvement to the code, and the results are put online quite often.

1.7. Automating Compilation with Ant

Problem

You get tired of typing javac and java commands.

Solution

Use the Ant program to direct your compilations.

Discussion

The intricacies of Makefiles have led to the development of a pure Java solution for automating the build process. Ant is free software; it is available in source form or ready-to-run from the Apache Foundation’s Jakarta Project web site, at http://jakarta.apache.org/ant/. Like make, Ant uses a file or files—written in XML—listing what to do and, if necessary, how to do it. These rules are intended to be platform-independent, though you can of course write platform-specific recipes if necessary.

To use Ant, you must create a 15 to 30 line file specifying various options. This file should be called build.xml; if you call it anything else, you’ll have to give a special command-line argument every time you run Ant. Example 1-1 shows the build script used to build the files in the starting directory. See Recipe 21.0 for a discussion of the XML syntax. For now, note that the <!- - tag begins an XML comment, which extends to the - -> tag.

Example 1-1. Ant example file (build.xml)

<project name="Java Cookbook Examples" default="compile" basedir=".">

  <!-- Set global properties for this build -->
  <property name="src" value="."/>
  <property name="build" value="build"/>
  <!-- Specify the compiler to use. 
    Using jikes is supported but requires rt.jar in classpath. -->
  <property name="build.compiler" value="modern"/>

  <target name="init">
    <!-- Create the time stamp -->
    <tstamp/>
    <!-- Create the build directory structure used by compile -->
    <mkdir dir="${build}"/>
  </target>

  <!-- Specify what to compile. This builds everything -->
  <target name="compile" depends="init">

    <!-- Compile the java code from ${src} into ${build} -->
    <javac srcdir="${src}" destdir="${build}"
          classpath="../darwinsys.jar"/>
  </target>

</project>

When you run Ant, it produces a reasonable amount of notification as it goes :

$ ant  compile
Buildfile: build.xml
Project base dir set to: /home/ian/javasrc/starting
Executing Target: init
Executing Target: compile
Compiling 19 source files to /home/ian/javasrc/starting/build
Performing a Modern Compile
Copying 22 support files to /home/ian/javasrc/starting/build
Completed in 8 seconds
$

See Also

The sidebar make Versus Ant; Ant: The Definitive Guide by Jesse E. Tilly and Eric M. Burke (O’Reilly).

1.8. Running Applets

Problem

You want to run an applet.

Solution

Write a class that extends java.applet.Applet; write some HTML and point a browser at it.

Discussion

An applet is simply a Java class that extends java.applet.Applet, and in doing so inherits the functionality it needs to be viewable inside a web page in a Java-enabled web browser.[5] All that’s necessary is an HTML page referring to the applet. This HTML page requires an applet tag with a minimum of three attributes , or modifiers: the name of the applet itself and its onscreen width and height in screen dots or pixels. This is not the place for me to teach you HTML syntax—there is some of that in Recipe 18.1—but I’ll show my HTML applet template file. Many of the IDEs write a page like this if you use their “build new applet” wizards:

<html>
<head><title>A Demonstration</title></head>
<body>
<h1>My TEMPLATE Applet</h1>
<applet code="CCC"  width="200" height="200">
</applet>
</body>
</html>

You can probably intuit from this just about all you need to get started. For a little more detail, see Recipe 18.1. Once you’ve created this file (replacing the CCC with the fully qualified class name of your applet—e.g., code="com.foo.MyApplet“) and placed it in the same directory as the class file, you need only tell a Java-enabled web browser to view the HTML page, and the applet should be included in it.

All right, so the applet appeared and it even almost worked. Make a change to the Java source and recompile. Click the browser’s Reload button. Chances are you’re still running the old version! Browsers aren’t very good at debugging applets. You can sometimes get around this by holding down the Shift key while you click Reload. But to be sure, use AppletViewer , a kind of mini-browser included in the JDK. You need to give it the HTML file, just like a regular browser. Sun’s AppletViewer (shown in Figure 1-9 under Windows) has an explicit Reload button that actually reloads the applet. And it has other features, such as debugging hooks, and other information displays. It also has a View Tag option that lets you resize the window until the applet looks best, and then you can copy and paste the tag—including the adjusted width and height attributes—into a longer HTML document.

Sun JDK AppletViewer

Figure 1-9. Sun JDK AppletViewer

The Mac OS X runtime includes both the standard AppletViewer from Sun and Apple’s own implementation (available as /Applications/Utilities/Java/Applet Launcher, shown in Figure 1-10), which is more colorful but slightly different. It has no Reload item in its menu; you close the Applet’s window and press the Launch button to reload. It also lets you load a new HTML file by typing in the URL field (or pressing Open... and browsing), which is more efficient than closing and restarting the traditional AppletViewer when the HTML file changes or when you want to invoke a different file.

Apple Mac OS X applet launcher

Figure 1-10. Apple Mac OS X applet launcher

Neither the Sun version nor the Apple version is a full applet runtime; features such as jumping to a new document do not work. But they are very good tools for debugging applets. Learn to use the AppletViewer that comes with your JDK or IDE.

See Also

The bad news about applets is that they either can’t use features of current Java versions or they run into the dreaded browser-incompatibility issue. In Recipe 23.6, I show how to use the Java Plug-in to get around this. In Recipe 23.13, I talk about Java Web Start, a relatively new technique for distributing applications over the Web in a way similar to how applets are downloaded; with JWS, programs are downloaded using HTTP but stored as, and run as, regular applications on your system’s local disk.

1.9. Dealing with Deprecation Warnings

Problem

Your code used to compile cleanly, but now it gives deprecation warnings.

Solution

You must have blinked. Either live—dangerously—with the warnings or revise your code to eliminate them.

Discussion

Each new release of Java includes a lot of powerful new functionality, but at a price: during the evolution of this new stuff, Java’s maintainers find some old stuff that wasn’t done right and shouldn’t be used anymore because they can’t really fix it. In building JDK 1.1, for example, they realized that the java.util.Date class had some serious limitations with regard to internationalization. Accordingly, many of the Date class methods and constructors are marked “deprecated.” To deprecate something means, according to the American Heritage Dictionary, to “express disapproval of; deplore.” Java’s developers are therefore disapproving of the old way of doing things. Try compiling this code:

import java.util.Date;

/** Demonstrate deprecation warning */
public class Deprec {

    public static void main(String[] av) {

        // Create a Date object for May 5, 1986
        // EXPECT DEPRECATION WARNING
        Date d = new Date(86, 04, 05);        // May 5, 1986
        System.out.println("Date is " + d);
    }
}

What happened? When I compile it, I get this warning:

C:\javasrc>javac Deprec.java
Note: Deprec.java uses or overrides a deprecated API.  Recompile with 
"-deprecation" for details.
1 warning
C:\javasrc>

So, we follow orders. Recompile with -deprecation (if using Ant, use <javac deprecation= 'true '...>) for details:

C:\javasrc>javac -deprecation Deprec.java
Deprec.java:10: warning: constructor Date(int,int,int) in class java.util.Date has 
been deprecated
                Date d = new Date(86, 04, 05);          // May 5, 1986
                         ^
1 warning

C:\javasrc>

The warning is simple: the Date constructor that takes three integer arguments has been deprecated. How do you fix it? The answer is, as in most questions of usage, to refer to the Javadoc documentation for the class. In Java 2, the introduction to the Date page says, in part:

The class Date represents a specific instant in time, with millisecond precision.

Prior to JDK 1.1, the class Date had two additional functions. It allowed the interpretation of dates as year, month, day, hour, minute, and second values. It also allowed the formatting and parsing of date strings. Unfortunately, the API for these functions was not amenable to internationalization. As of JDK 1.1, the Calendar class should be used to convert between dates and time fields and the DateFormat class should be used to format and parse date strings. The corresponding methods in Date are deprecated.

And more specifically, in the description of the three-integer constructor, it says:

Date(int year, int month, int date)

Deprecated. As of JDK version 1.1, replaced by Calendar.set(year + 1900, month, date) or GregorianCalendar(year + 1900, month, date).

As a general rule, when something has been deprecated, you should not use it in any new code and, when maintaining code, strive to eliminate the deprecation warnings.

The main areas of deprecation warnings in the standard API are Date (as mentioned), JDK 1.0 event handling, and some methods—a few of them important—in the Thread class.

You can also deprecate your own code. Put in a doc comment (see Recipe 23.2) with the @deprecated tag immediately before the class or method you wish to deprecate.

1.10. Conditional Debugging Without #ifdef

Problem

You want conditional compilation and Java doesn’t seem to provide it.

Solution

Use constants, command-line arguments, or assertions (Recipe 1.12), depending upon the goal.

Discussion

Some older languages such as C, PL/I, and C++ provide a feature known as conditional compilation. Conditional compilation means that parts of the program can be included or excluded at compile time based upon some condition. One thing it’s often used for is to include or exclude debugging print statements. When the program appears to be working, the developer is struck by a fit of hubris and removes all the error checking. A more common rationale is that the developer wants to make the finished program smaller—a worthy goal—or make it run faster by removing conditional statements.

Conditional compilation?

Although Java lacks any explicit conditional compilation, a kind of conditional compilation is implicit in the language. All Java compilers must do flow analysis to ensure that all paths to a local variable’s usage pass through a statement that assigns it a value first, that all returns from a function pass out via someplace that provides a return value, and so on. Imagine what the compiler will do when it finds an if statement whose value is known to be false at compile time. Why should it even generate code for the condition? True, you say, but how can the results of an if statement be known at compile time? Simple: through final boolean variables. Further, if the value of the if condition is known to be false, then the body of the if statement should not be emitted by the compiler either. Presto—instant conditional compilation!

// IfDef.java
final boolean DEBUG = false;
System.out.println("Hello, World ");
if (DEBUG) {
        System.out.println("Life is a voyage, not a destination");
}

Compilation of this program and examination of the resulting class file reveals that the string “Hello” does appear, but the conditionally printed epigram does not. The entire println has been omitted from the class file. So Java does have its own conditional compilation mechanism.

darian$ jr IfDef
 jikes +E  IfDef.java
 java IfDef
Hello, World
darian$ strings IfDef.class | grep Life # not found!
darian$ javac IfDef.java # try another compiler
darian$ strings IfDef.class | grep Life # still not found!
darian$

What if we want to use debugging code similar to this but have the condition applied at runtime? We can use System.properties (Recipe 2.2) to fetch a variable. Recipe 1.11 uses my Debug class as an example of a class whose entire behavior is controlled this way.

But this is as good a place as any to interject about another feature—inline code generation. The C/C++ world has a language keyword inline, which is a hint to the compiler that the function (method) is not needed outside the current source file. Therefore, when the C compiler is generating machine code, a call to the function marked with inline can be replaced by the actual method body, eliminating the overhead of pushing arguments onto a stack, passing control, retrieving parameters, and returning values. In Java, making a method final enables the compiler to know that it can be inlined, or emitted in line. This is an optional optimization that the compiler is not obliged to perform, but may for efficiency.

See Also

Recipe 1.12.

1.11. Debugging Printouts

Problem

You want to have debugging statements left in your code enabled at runtime.

Solution

Use my Debug class.

Discussion

Instead of using the conditional compilation mechanism of Recipe Recipe 1.10, you may want to leave your debugging statements in the code but enable them only at runtime when a problem surfaces. This is a good technique for all but the most compute-intensive applications, because the overhead of a simple if statement is not all that great. Let’s combine the flexibility of runtime checking with the simple if statement to debug a hypothetical fetch( ) method (part of Fetch.java):

String name = "poem";
if (System.getProperty("debug.fetch") != null) {
    System.err.println("Fetching " + name);
}
value = fetch(name);

Then, we can compile and run this normally and the debugging statement is omitted. But if we run it with a -D argument to enable debug.fetch, the printout occurs:

> java Fetch          # See? No output
> java -Ddebug.fetch Fetch
Fetching poem
>

Of course this kind of if statement is tedious to write in large quantities, so I have encapsulated it into a Debug class, which is part of my com.darwinsys.util package. Debug.java appears in full in Recipe 1.17 at the end of this chapter. My Debug class also provides the string “debug.” as part of the argument to System.getProperty( ) , so we can simplify the previous Fetch example as follows (code in FetchDebug.java):

String name = "poem", value;
Fetch f = new Fetch( );
Debug.println("fetch", "Fetching " + name);
value = f.fetch(name);

Running it behaves identically to the original Fetch:

> java FetchDebug     # again, no output
> java -Ddebug.fetch FetchDebug
Fetching poem
>

See Also

Some more comprehensive and flexible “debug printout” mechanisms—including ones that can log across a network connection—are covered in Recipes Recipe 17.7, Recipe 17.8, and Recipe 17.9.

1.12. Maintaining Program Correctness with Assertions

Problem

You want to leave tests in your code but not have runtime checking overhead until you need it.

Solution

Use the JDK 1.4 Assertions mechanism.

Discussion

JDK 1.4 introduced a new keyword into the language: assert. The assert keyword takes two arguments separated by a colon (by analogy with the conditional operator): an expression that is asserted by the developer to be true, and a message to be included in the exception that is thrown if the expression is false. To provide for backward compatibility with programs that might have used “assert” as an identifier name on prior JDK versions, JDK 1.4 requires a command-line switch (-source 1.4) that must be provided for assert to be recognized as a keyword. Normally, assertions are meant to be left in place (unlike quick and dirty print statements, which are often put in during one test and then removed). To reduce runtime overhead, assertion checking is not enabled by default; it must be enabled explicitly with the -enableassertions (or -ea) command-line flag. Here is a simple demo program that shows the use of the assertion mechanism:

ian:147$  cd testing;
ian:148$ cat AssertDemo.java
public class AssertDemo {
        public static void main(String[] args) {
                int i = 4;
                if (args.length == 1) {
                        i = Integer.parseInt(args[0]);
                }
                assert i > 0 : "i is non-positive";
                System.out.println("Hello after an assertion");
        }
}
ian:149$ javac -source 1.4 AssertDemo.java  # will not compile without 1.4 flag
ian:150$ java AssertDemo  -1
Hello after an assertion
ian:151$ java -ea  AssertDemo  -1
Exception in thread "main" java.lang.AssertionError: i is non-positive
        at AssertDemo.main(AssertDemo.java:15)
ian:152$

1.13. Debugging with JDB

Problem

The use of debugging printouts and assertions in your code is still not enough.

Solution

Use a debugger, preferably the one that comes with your IDE.

Discussion

The JDK includes a command-line-based debugger, jdb, and any number of IDEs include their own debugging tools. If you’ve focused on one IDE, learn to use the debugger that it provides. If you’re a command-line junkie, you may want to learn at least the basic operations of jdb.

Here is a buggy program. It intentionally has bugs introduced so that you can see their effects in a debugger:

/** This program exhibits some bugs, so we can use a debugger */
public class Buggy {
    static String name;

    public static void main(String[] args) {
        int n = name.length( );    // bug # 1

        System.out.println(n);

        name += "; The end.";    // bug #2
        System.out.println(name); // #3
    }
}

Here is a session using jdb to find these bugs:

ian> java Buggy
Exception in thread "main" java.lang.NullPointerException
        at Buggy.main(Compiled Code)
ian> jdb Buggy
Initializing jdb...
0xb2:class(Buggy)
> run
run Buggy 
running ...
main[1] 
Uncaught exception: java.lang.NullPointerException
        at Buggy.main(Buggy.java:6)
        at sun.tools.agent.MainThread.runMain(Native Method)
        at sun.tools.agent.MainThread.run(MainThread.java:49)

main[1] list
2          public class Buggy {
3               static String name;
4          
5               public static void main(String[] args) {
6       =>              int n = name.length( );  // bug # 1
7          
8                       System.out.println(n);
9          
10                      name += "; The end.";   // bug #2
main[1] print Buggy.name
Buggy.name = null
main[1] help
** command list **
threads [threadgroup]     -- list threads
thread <thread id>        -- set default thread
suspend [thread id(s)]    -- suspend threads (default: all)
resume [thread id(s)]     -- resume threads (default: all)
where [thread id] | all   -- dump a thread's stack
wherei [thread id] | all  -- dump a thread's stack, with pc info
threadgroups              -- list threadgroups
threadgroup <name>        -- set current threadgroup

print <id> [id(s)]        -- print object or field
dump <id> [id(s)]         -- print all object information

locals                    -- print all local variables in current stack frame

classes                   -- list currently known classes
methods <class id>        -- list a class's methods

stop in <class id>.<method>[(argument_type,...)] -- set a breakpoint in a method
stop at <class id>:<line> -- set a breakpoint at a line
up [n frames]             -- move up a thread's stack
down [n frames]           -- move down a thread's stack
clear <class id>.<method>[(argument_type,...)]   -- clear a breakpoint in a method
clear <class id>:<line>   -- clear a breakpoint at a line
step                      -- execute current line
step up                   -- execute until the current method returns to its caller
stepi                     -- execute current instruction
next                      -- step one line (step OVER calls)
cont                      -- continue execution from breakpoint

catch <class id>          -- break for the specified exception
ignore <class id>         -- ignore when the specified exception

list [line number|method] -- print source code
use [source file path]    -- display or change the source path

memory                    -- report memory usage
gc                        -- free unused objects

load classname            -- load Java class to be debugged
run <class> [args]        -- start execution of a loaded Java class
!!                        -- repeat last command
help (or ?)               -- list commands
exit (or quit)            -- exit debugger
main[1] exit
ian>

Many other debuggers are available; a look in the current Java magazines will inform you of them. Many of them work remotely since the Java Debugger API (that which the debuggers use) is network-based.

1.14. Unit Testing: Avoid the Need for Debuggers

Problem

You don’t want to have to debug your code.

Solution

Use unit testing to validate each class as you develop it.

Discussion

Stopping to use a debugger is time-consuming; it’s better to test beforehand. The methodology of unit testing has been around for a long time but has been overshadowed by newer methodologies. Unit testing is a tried and true means of getting your code tested in small blocks. Typically, in an OO language like Java, unit testing is applied to individual classes, in contrast to “black box” testing where the entire application is tested.

I have long been an advocate of this very basic testing methodology. Indeed, developers of the software methodology known as Extreme Programming (XP for short; see http://www.extremeprogramming.org) advocate writing the unit tests before you write the code, and they also advocate running your tests almost every time you compile. This group of extremists has some very well-known leaders, including Gamma and Beck of Design Patterns fame. I definitely go along with their advocacy of unit testing.

Indeed, many of my classes come with a “built-in” unit test. Classes that are not main programs in their own right often include a main method that just tests out the functionality of the class. Here is an example:

/** A simple class used to demonstrate unit testing. */
public class Person {
    protected String fullName;
    protected String firstName, lastName;

    /** Construct a Person using his/her first+last names. */
    public Person(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    /** Get the person's full name */
    public String getFullName( ) {
        if (fullName != null)
            return fullName;
        return firstName + " " + lastName;
    }

    /** Simple test program. */
    public static void main(String[] argv) {
        Person p = new Person("Ian", "Darwin");
        String f = p.getFullName( );
        if (!f.equals("Ian Darwin"))
            throw new IllegalStateException("Name concatenation broken");
        System.out.println("Fullname " + f + " looks good");
    }
}

What surprised me is that, before encountering XP, I used to think I did this often, but an actual inspection of two projects indicated that only about a third of my classes had test cases, either internally or externally. Clearly what is needed is a uniform methodology. That is provided by JUnit.

JUnit is a Java-centric methodology for providing test cases. You can freely download JUnit from the obvious web site, http://www.junit.org. JUnit is a very simple but useful testing tool. It is easy to use—you just write a test class that has a series of methods whose names begin with test. JUnit uses introspection (see Chapter 25) to find all these methods, and then it runs them for you! Extensions to JUnit handle tasks as diverse as load testing and testing Enterprise JavaBeans (EJBs); the JUnit web site provides links to these extensions.

How do you get started using JUnit? All that’s necessary is to write a test. Here I have excerpted the test from my Person class and placed it into a class PersonTest . Note the obvious naming pattern.

import junit.framework.*;

/** A simple test case for Person */
public class PersonTest extends TestCase {

    /** JUnit test classes require this constructor */
    public PersonTest(String name) {
        super(name);
    }

    public void testNameConcat( ) {
        Person p = new Person("Ian", "Darwin");
        String f = p.getFullName( );
        assertEquals(f, "Ian Darwin");
    }

}

To run it, I need only compile the test and invoke the test harness junit:

daroad.darwinsys.com$ javac PersonTest.java
daroad.darwinsys.com$ java junit.textui.TestRunner PersonTest
.
Time: 0.188
 
OK (1 tests)
 
daroad.darwinsys.com$

The use of a full class name is a bit tedious, so I have a script named jtest that invokes it; I just say jtest Person and it runs the previous command for me.

#!/bin/sh

exec java junit.textui.TestRunner ${1}Test

In fact, even that is tedious, so I usually have a regress target in my Ant scripts. There is a junit task in Ant’s “Optional Tasks” package.[6] Using it is easy:

<target  name="regress" depends="build">
    <junit>
          <test name="PersonTest" />
    </junit> 
</target>

See Also

If you prefer flashier GUI output, several JUnit variants (built using Swing and AWT; see Chapter 14) will run the tests with a GUI.

JUnit offers classes for building comprehensive test suites and comes with considerable documentation of its own; download the program from the web site listed earlier.

Also, for testing graphical components, I have developed a simple component tester, described in Recipe 13.2.

Remember: Test early and often!

1.15. Getting Readable Tracebacks

Problem

You’re getting an exception stack trace at runtime, but most of the important parts don’t have line numbers.

Solution

Be sure you have compiled with debugging enabled. On older systems, disable JIT and run it again, or use the current HotSpot runtime.

Discussion

When a Java program throws an exception, the exception propagates up the call stack until there is a catch clause that matches it. If none is found, the Java interpreter program that invoked your main( ) method catches the exception and prints a stack traceback showing all the method calls that got from the top of the program to the place where the exception was thrown. You can print this traceback yourself in any catch clause: the Throwable class has several methods called printStackTrace( ).

The traceback includes line numbers only if they were compiled in. When using Sun’s javac, this is the default. When using Ant’s javac task, this is not the default; you must be sure you have used <javac debug="true" ...> in your build.xml file if you want line numbers.

The Just-In-Time (JIT) translation process consists of having the Java runtime convert part of your compiled class file into machine language so that it can run at full execution speed. This is a necessary step for making Java programs run under interpretation and still be acceptably fast. However, in the early days of Java, its one drawback was that it generally lost the line numbers. Hence, when your program died, you still got a stack traceback but it no longer showed the line numbers where the error occurred. So we have the trade-off of making the program run faster, but harder to debug. Modern versions of Sun’s Java runtime include the HotSpot Just-In-Time translator, which doesn’t have this problem.

If you’re still using an older (or non-Sun) JIT, there is a way around this. If the program is getting a stack traceback and you want to make it readable, you need only disable the JIT processing. How you do this depends upon what release of Java you are using. On JDK 1.2 and above, you need only set the environment variable JAVA_COMPILER to the value NONE, using the appropriate set command:

C:\> set JAVA_COMPILER=NONE # DOS, Windows
setenv JAVA_COMPILER NONE                   # Unix Csh
export JAVA_COMPILER=NONE # Unix Ksh, modern sh

To make this permanent, you would set it in the appropriate configuration file on your system; on recent versions of Windows, you can also set environment variables through the Control Panel.

An easier way to disable JIT temporarily, and one that does not require changing the setting in your configuration files or Control Panel, is the -D command-line option, which updates the system properties. Just set java.compiler to NONE on the command line:

               java -Djava.compiler=NONE  myapp

Note that the -D command-line option overrides the setting of the JAVA_COMPILER environment variable.

As mentioned, Sun’s HotSpot JIT runtime—included in most modern Java releases—generally provides tracebacks, even with JIT mode enabled.

1.16. Finding More Java Source Code

Problem

You want even more Java code examples to look at.

Solution

Use The Source, Luke.

Discussion

Java source code is everywhere. As mentioned in the Preface, all the code examples from this book can be downloaded from the O’Reilly site (http://java.oreilly.com/). What I didn’t tell you, but what you might have realized by extension, is that the source examples from all the O’Reilly Java books are available there, too: the examples from Java Examples in a Nutshell, Java Swing—all of them.

Another valuable resource is the source code for the Java API. You may not have realized it, but the source code for all the public parts of the Java API are included with each release of the Java Development Kit. Want to know how java.util.ArrayList actually works? You have the source code. Got a problem making a JTable behave? Sun’s JDK includes the source for all the public classes! Look for a file called src.zip or src.jar ; some versions unzip this and some do not.

If that’s not enough, you can get the source for the whole JDK for free over the Internet, just by committing to the Sun Java Community Source License and downloading a large file. This includes the source for the public and non-public parts of the API, as well as the compiler (written in Java) and a large body of code written in C/C++ (the runtime itself and the interfaces to the native library). For example, java.io.Reader has a method called read( ) , which reads bytes of data from a file or network connection. This is written in C because it actually calls the read( ) system call for Unix, Windows, Mac OS, BeOS, or whatever. The JDK source kit includes the source for all this stuff.

And ever since the early days of Java, there have been a number of web sites set up to distribute free software or open source Java, just as with most other modern “evangelized” languages, such as Perl, Python, Tk/Tcl, and others. (In fact, if you need native code to deal with some oddball filesystem mechanism in a portable way, beyond the material in Chapter 11 of this book, the source code for these runtime systems might be a good place to look.)

I’d like to mention several web sites of lasting value:

  • Gamelan has been around almost forever (in Java time). The URL http://www.gamelan.com still worked the last I checked, but the site has been (naturally) commercialized, and it is now part of http://www.developer.com.

  • Java.Net is a collaboration between Sun and O’Reilly, and it contains a number of interesting Java projects.

  • The Giant Java Tree is more recent and is limited to code that is covered by the GNU Public License. There is a great deal of source code stored there, all of which can be freely downloaded. See http://www.gjt.org.

  • The CollabNet open source marketplace is not specific to Java but offers a meeting place for people who want open source code written and those willing to fund its development. See http://www.collab.net.

  • SourceForge, also not specific to Java, offers free public hosting of open source projects. See http://sourceforge.net.

  • Finally, the author of this book maintains a small Java site at http://www.darwinsys.com/java/, which may be of value. It includes a listing of Java resources and material related to this book.

As with all free software, please be sure that you understand the ramifications of the various licensing schemes. Code covered by the GPL, for example, automatically transfers the GPL to any code that uses even a small part of it. And even once looking at Sun’s Java implementation details (the licensed download mentioned previously) may prevent you from ever working on a “clean-room” reimplementation of Java, the free software Kaffe, or any commercial implementation. Consult a lawyer. Your mileage may vary. Despite these caveats, the source code is an invaluable resource to the person who wants to learn more Java.

1.17. Program: Debug

Most of the chapters of this book end with a “Program” recipe that illustrates some aspect of the material covered in the chapter. Example 1-2 is the source code for the Debug utility mentioned in Recipe 1.11.

Example 1-2. Debug.java

package com.darwinsys.util;

/** Utilities for debugging
 */
public class Debug {
    /** Static method to see if a given category of debugging is enabled.
     * Enable by setting e.g., -Ddebug.fileio to debug file I/O operations.
     * Use like this:<BR>
     * if (Debug.isEnabled("fileio"))<BR>
     *     System.out.println("Starting to read file " + fileName);
     */
    public static boolean isEnabled(String category) {
        return System.getProperty("debug." + category) != null;
    }

    /** Static method to println a given message if the
     * given category is enabled for debugging.
     */
    public static void println(String category, String msg) {
        if (isEnabled(category))
            System.out.println(msg);
    }
    /** Same thing but for non-String objects (think of the other
     * form as an optimization of this).
     */
    public static void println(String category, Object stuff) {
        println(category, stuff.toString( ));
    }
}


[1] There is humor in the phrase “old Java code,” which should be apparent when you realize that Java had been in circulation for under five years at the time of this book’s first edition.

[2] It takes too long to say, or type, Integrated Development Environment, so I’ll use the term IDE from here on. I know you’re good at remembering acronyms, especially TLAs.

[3] WebSphere Studio Application Developer describes itself, in its online help, as “IBM’s implementation of Eclipse” and gives a link to http://www.eclipse.org/.

[4] If you have a file called com-darwinsys-util.jar, that file contains the old API described in the first edition and will not work with the examples in this book.

[5] Includes Netscape/Mozilla, Apple Safari, MS Internet Explorer, KDE Konqueror, and most others.

[6] In some versions of Ant, you may need an additional download for this to function.

Get Java Cookbook, 2nd Edition now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.