Chapter 42

Developing Java Applets

by Paul Santa Maria


CONTENTS

"Java," to quote its authors on the subject, "is a simple, robust, object-oriented, platform-independent, multi-threaded, dynamic, general-purpose, programming environment."

Although this rather immodest sentence was meant as a humorous reference to all of the marketing buzzwords and hoopla surrounding Java, the authors quite seriously go on to back up each of their claims. You can read the entire white paper from which this quotation was taken at Sun Microsystems' Web site at http://java.sun.com/java.sun.com/allabout.html.

After you learn the rudiments of programming in Java and you've had a chance to experiment with this new language for a while, then you, too, will share the excitement and agree with some (or all!) of the preceding claims. The intent is not to show you everything, but to give you a practical, hands-on "jump start" in learning the Java language. Read on to learn what Java is, what it is not, and how to use it effectively on your own Web pages.

What Exactly Is Java?

The term Java can mean any of several completely different things, depending on whom you talk to, such as:

Why Java?

At the time of this writing (mid-1996), the Internet is still in its infancy as a medium for dynamic mass communications.

The basic technology that makes up the Internet has been around for many years. But it was the introduction of a simple graphical user interface-the Web browser-that suddenly made it so incredibly popular among millions of users worldwide.

But most Web pages now seen on the Internet have a relatively primitive, static character. Take away all the gaudy flying logos and ticker tapes, and you're usually left with one of the following:

Although forms and image maps allow a measure of user interaction, all of the main processing is done remotely on the Web server. For any frequently used site (such as www.netscape.com), this incurs a considerable load on the server. Moreover, the final result of all of the server's hard work is (you guessed it!) more static HTML, which is downloaded only to be passively displayed by your Web browser.

This kind of interaction is not the style of computing preferred by a generation of users weaned on productivity tools such as VisiCalc, Adobe PageMaker, Microsoft Word, PowerPoint, Lotus Notes, and, above all, PGA Golf. We are all used to the benefits of running our applications locally, on our very own personal computers.

Java promises an alternative model for Web content-a model much closer to the spirit of computer programs people are running on their own PCs. The crucial difference between a Java-based program and a traditional PC application is that Java programs are, by nature, network-aware and truly distributed. As creatures of the Internet, Java programs offer all of the benefits of locally executed programs: responsiveness, the capability to take advantage of local computing resources, and so on. Yet, at the same time, Java programs break the shackles of being tied to a single PC. They can suddenly take advantage of computing resources from the entire, global Internet! You'll get a taste of this awesome potential as you continue to learn about writing Java applets.

In the context of the Web, Java applets offer the following advantages:

Basic Language Constructs

Java syntax is very similar to C and C++. At first glance, this makes the language immediately accessible to the millions of practicing C/C++ programmers. But as you'll see in the next section, Java and C might look very much alike, but they are not identical, and sometimes apparent similarities can be misleading.

The following four tables, 42.1 through 42.4, summarize Java's basic language constructs.

Table 42.1  Basic Language Constructs (Java Types)

TypeExample Notes
booleanboolean flag = false; A Java boolean is just true or false. It cannot be cast to char or int.
charchar c[] = {'A','\uu42','C'}; A Java char is a 16-bit Unicode character. You'll usually use the Java class String instead.
Bytebyte b = 0x7f; 8-bit signed integer (-127 .. 127)
shortshort s = 32767; 16-bit signed integer (-32,768 .. 32767)
intint i = 2; 32-bit signed integer
longlong l = 2L; 64-bit signed integer. Note the suffix L is required for a long (decimal) literal.
Floatfloat x = 2.0F; 32-bit IEEE754 number. Note the suffix F is required for a float literal.
Doubledouble d = 2.0; 64-bit IEEE754 number (15 significant digits)

TIP
Java is a strongly-typed language. You must explicitly declare the "type" of every single variable that you use, and you can't arbitrarily mix or inter-convert types as easily as you can in C++ or Basic
Java was deliberately engineered this way. In the long run, the use of strong typing tends to eliminate many common bugs and yields safer, more robust software products. But for novice Java programmers, the compiler's strict typing rules can be a source of frustration.
The easiest way to deal with this problem is to focus on classes instead of primitive data types. By thinking at this higher level (at the class level), you'll probably need fewer primitive types and they'll be less likely to interact with one another in troublesome ways. By forcing yourself to think in terms of Java "classes," you'll save yourself some headaches, and you'll probably end up with simpler, more robust program designs, too!

Table 42.2  Basic Language Constructs (Java Operators)

OperatorDescription
.Member selection
[]Array subscript
()Parenthesis/Function call
++, -Auto-increment/Auto-decrement
*, /, %Arithmetic: Multiply, divide, modulo
+, -,Arithmetic: Add, subtract
<<, >>, >>>Bitwise: Shift left, Arithmetic shift right, and Logical shift right
<=, <, >, >=Equality: Less than or equal to, Less than, Greater than, Greater than or equal to
==, !=Equality: Equal to, Not equal to
&, |, ^, ~Bitwise: AND, OR, Exclusive Or (XOR), and NOT
&&, ||, !Logical: AND, OR, and NOT
? :Conditional expression
=Simple assignment
*=,/=, %=, +=, -=, &=,Complex assignment |=, ^=, <<=, >>=,>>>=

TIP
The operators in this table are arranged in order of precedence. For example, the compiler will treat the expression 2 + 2 * 2 ^ 2 as 2 + (2 * (2 ^ 2)), executing 2 XOR 2 first, 2 * the result next, and so on
In your own Java code, always make liberal use of parentheses to explicitly state the order in which you want the operations in your expression to be carried out. Using parentheses instead of relying on the default precedence hierarchy will help you avoid a common source of bugs.

Table 42.3  Basic Language Constructs (Control Flow)

ConstructExample
if...then...elseif (i >= salesGoal) { ... }
forfor (i = 0; i < maxItems; i++) {...}
whilewhile (i < salesGoal) { ... }
do...whiledo { ... } while (i < salesGoal);
switch (...) caseswitch (i) { case 1: ... break; }
breakwhile (i < salesGoal) { if (I==10) break;...}
continuewhile (i < salesGoal) { if (I==10) continue; ... }
labelled breakwhile (i < salesGoal) { if (I==10) break my_label;...}

Table 42.4  Basic Language Constructs (Java Comments)

Comment styleFormat Notes
C comments/* ... */ Can span multiple lines
C++ comments// ... Comment stops at the end of the line: less prone to error
Javadoc comments/** ... */ Appropriate for header comments: lets you auto-generate program documentation

ON THE WEB
http://java.sun.com/newdocs.html  This site will give you all the details on Sun's official Java documentation, including reference manuals and language tutorials

Leveraging Java Classes and Packages

Although operators and data types are obviously very important in Java, classes are where the real action is.

In his text Object-Oriented Modeling and Design, James Rumbaugh defined a "class" as describing "...a group of objects with similar properties (attributes), common behavior (operations), common relationships to other objects, and common semantics." An object, on the other hand, is simply an instance of a class, dynamically created by the program during runtime. In other words, classes are definitions; objects are the real thing.

In Java, everything is a class. Unlike C and C++, Java has no structs and no free subprograms (a "free subprogram" is a subroutine or function that exists independently of a class). Most of the power of C++ stems from the simple notion of extending C's basic struct into the notion of a C++ class, which encapsulates both state (program data) and methods (a program's algorithms) into a single logical entity. Java completes this transition by recognizing that, after you have the power of classes, structs become irrelevant!

Java was designed to be both a simpler and a safer language than C++. Many features of C++ such as multiple inheritance were deliberately left out of Java because Java's authors felt that they could make their new language less complex and make Java programs less prone to common C++ programming and design errors.

Table 42.5 gives a brief overview of Java classes in comparison to C++.

Table 42.5  Java Class Versus C Class Constructs

Construct
C++
Java
Class
Yes
Yes
Single Inheritance
Yes
Yes
Multiple Inheritance
Yes
No
Constructors
Yes
Yes
Destructors
Yes
No
Templates
Yes
No
Packages
No
Yes
Interfaces
No
Yes
Packages
No
Yes
Interfaces
No
Yes

Basically, traditional methods force you to "think like the machine" and break things down into modules, variables, parameters, and the like. Object-oriented methods allow you to think at a much higher level-in terms of objects, their behavior, and how they relate to one another.

The interesting thing is that Java (unlike, for example, C++) forces you to think in an object-oriented style. When you work with Java, you will probably find yourself spending most of your development time figuring out what "objects" your program needs, and browsing to see whether your library already has existing (canned) classes that you can inherit from, thus reusing existing code with little or no additional effort on your part!

This is a marked contrast from traditional programming styles in languages such as FORTRAN, C, or Pascal, where the bulk of your effort goes into "decomposing" a problem into modules, then creating algorithms the modules use to process data. In many subtle (and many not so subtle!) ways, Java almost forces the programmer to abandon old procedural habits in favor of a more object-oriented perspective.

We will return to this discussion later. For now, let's get on with the fun stuff-coding and running our very first Java applet!

Java 101: HelloWorld

At this writing, Java is so new that there are relatively few decent tools for creating Java applications. Symantec's CafŽ Lite, Borland C++ 5.0, and Microsoft Visual J++ come immediately to mind as excellent, GUI-based development tools.

But for purposes of our discussion, let's stick with the original Java tools that are freely available from the creators of Java, Sun Microsystems. These tools are the following:

You can download a free copy of the Java JDK at http://www.javasoft.com/.

TIP
Java requires a 32-bit operating system and support for long, case-sensitive file names. In the PC arena, Java supports only Windows 95 or Windows NT

First, create a program source file, as shown in Listing 42.1.


Listing 42.1  HelloWorld.java-First Java Applet
HelloWorld.java
/**
 * HelloWorld: Rudimentary Java applet
 *
 * @version 1.0, DATE: 8.11.96
 * @author Paul Santa Maria
 */
import java.applet.*;
import java.awt.*;              // User Interface components

//
// MyCanvas: graphics area to draw "Hello World!"
//
class MyCanvas extends Canvas
{
  public void paint (Graphics g)
  {
    g.drawString ("Hello from Java!", 0, 50);
  }
}

//
// HelloWorld: sample program "main"
//
public class HelloWorld extends Applet
{
  private MyCanvas canvas;

  // init: applet initialization code goes here
public void init ()
  {
     setLayout (new BorderLayout());
     canvas = new MyCanvas ();
     add ("Center", canvas);
   }

  // handleEvent: give us a way to gracefully exit the program
  public boolean handleEvent (Event evt)
  { if (evt.id == Event.WINDOW_DESTROY)
        System.exit (0);
     return false;
  }
}

TIP
You must use a text editor that supports long, case-sensitive file names
The versions of Notepad, WordPad, and Edit that come with Windows 95 work fine. Word for Office 4.0 also works. Earlier versions of Word for 16-bit Windows do not work.
Your Java source file must have the same name as the main class. That is, you must name this file HelloWorld.java, which corresponds to the main class HelloWorld.
Furthermore, the capitalization must also match exactly. If your class is named HelloWorld but your source file is named Helloworld.java (note the lowercase "w"), the program will not compile!
This close relationship between class names and program source files is another of many reasons why it is not practical to port Java development tools to DOS or Windows 3.1 (neither of which supports long or mixed-case file names)!
Complete source code for each of these programs is included on the accompanying CD-ROM.

Basically, all you're doing here is using the canned functionality that's already built in to the Java class applet, and tweaking it slightly for your purposes by using inheritance (for example, class HelloWorld extends applet)-and that's the entire program!

We're also doing the same thing with MyCanvas. We just inherit from some pre-existing class that does almost what we want, tweak it slightly with some new functionality, then shamelessly use the whole thing as though we had done all the work ourselves.

You may recall from our earlier discussion that Java applets are somewhat different beasts than stand-alone Java applications. Applets are specifically designed to run from within the context of an HTML Web page. So let's write a simple Web page to test our new applet (see Listing 42.2).


Listing 42.2  Example.html-HTML Web Page that Calls the Applet
<HTML>
<TITLE>Hello World!</TITLE>
<BODY>
<H1>HelloWorld: a first Java Applet:</H1>
<APPLET CODE="HelloWorld.class" WIDTH=120 HEIGHT=120>
If you can read this, then your browser is not set up for Java...
</APPLET>
<HR>
<A HREF="HelloWorld.java">The source.</A>
</BODY>
</HTML>

TIP
Your HTML source file is not subject to the same strict rules about long file names and case-sensitivity as your Java source files

Finally, let's write a convenient batch file to compile and execute our program (see Listing 42.3).


Listing 42.3  Demo.bat-Windows Batch File for Compiling and Running the Applet
demo.bat:
@rem Compile and execute  "Hello world" sample program
javac HelloWorld.java
appletviewer example.html

TIP
This method assumes that you have SunSoft's text-oriented javac compiler and appletviewer installed on your system, and that you have your Windows 95 PATH and CLASSPATH environment variables set correctly
Following is a sample from an Autoexec.bat file that sets these two variables:
PATH=c:\windows;c:\windows\command;c:\java\bin
CLASSPATH=c:\java\lib;
Note that Setup.exe for the Windows 95 or Windows NT JDK should automatically install these definitions in your Autoexec.bat for you.

Figure 42.1 shows the result of our very first program, as seen through SunSoft's appletviewer.

Figure 42.1 : The JDK provides a simple appletviewer for previewing and testing your applets.

Running Your HelloWorld Applet from a Web Browser

Although you'll find it convenient to use appletviewer (or your Java compiler's IDE) as you first develop your applets, you should always test them on a real Web browser before you actually publish your applets to the outside world.

Let's now run the same Java program from Netscape Navigator (see Figure 42.2).

Figure 42.2 : You can also view your applet through any Java-enabled Web browser.

You may have noticed that none of your HTML (HelloWorld: a first Java Applet, and so on) showed up when you looked at it through appletviewer. This is because it is not a full-fledged Web browser. appletviewer is intended only for viewing applets! Nevertheless, as you start coding and testing, you will undoubtedly find appletviewer a more convenient test bed until you get your applets completely up and running.

You may have also noticed that when you viewed your applet under Netscape, the applet looked just like the surrounding HTML: just plain, old boring text. Fear not! We're going to get into graphics in our next, only slightly more difficult, example (a Mandelbrot Set program).

Troubleshooting HelloWorld

Even with an applet as simple as this, there are a number of things that could go wrong. Let's take a look at some common "gotcha's":

PATH=c:\windows;c:\windows\command;c:\java\bin
CLASSPATH=c:\java\lib;.

HelloWorld Class Diagram

Sometimes, programmers become impatient with the analysis and design phases of software development, preferring to jump right in and start coding. This attitude is often justified. For small programs like those found in textbooks, it makes little sense to go to all the trouble of requirements, analysis, design, integration, test, and so on. For a small program, you just fire up your compiler, whip up some code, and voil‡!-you're done!

But life just isn't like that for larger, more complex, or, dare we say it, mission-critical applications. For projects like those, we all need to sit down and plan ahead! One of the beautiful things about Java is that it's expressly designed to scale up to large, mission-critical projects. In all honesty, you'll be doing yourself a tremendous favor if you get into the habit of thinking about design issues now, when you're starting out on the simple programs. As a consequence, it will be second-nature for you later when you need it on your large-scale projects.

Let's look at a class hierarchy diagram for our simple HelloWorld program (see Figure 42.3).

Figure 42.3 : Class diagrams are powerful design tools that show you what your classes do, what they contain, and how they relate to each other.

You may recognize the two boxes HelloWorld and MyCanvas. These correspond to the two classes, HelloWorld and MyCanvas, that we used in our program.

The lines connecting HelloWorld with Applet and MyCanvas with Canvas illustrate an inheritance relationship. This is often called an is-a relationship; class HelloWorld is-an Applet; MyCanvas is-a Canvas. Applet and Canvas are called parent classes; MyCanvas and HelloWorld are called child or sub- classes.

The boxes HelloWorld and MyCanvas also list each class's methods. You may want to avoid cluttering your diagram by listing only the few most important methods. In this diagram, we chose to list all the methods that were overridden from the base class: init(), handleEvent(), and paint(). We also showed the constructor method MyCanvas().

The line that connects HelloWorld and MyCanvas is a use, or has-a relationship. This means that class HelloWorld (which is a kind of applet) makes use of MyCanvas (which is, in turn, a subclass of Canvas).

Let's continue and try some Java graphics.

TIP
If you're interested in reading more on the subject, two excellent books are the following
  • Object-Oriented Analysis and Design With Applications, Second Edition, by Grady Booch, (Benjamin Cumming, 1994)
  • Object-Oriented Modeling and Design, by Rumbaugh, Blaha, Premerlani, Eddy, and Lorensen, (Prentice-Hall, 1991)

Using the Java API Manual

One of the nifty things about using Java is that all of the principal documentation is completely online in Web format. The Java API manual is automatically on your hard disk when you install the JDK (see Figure 42.4). The latest-and-greatest version of the manual is also available directly on the Internet at the following addresses:

http://www.javasoft.com/doc/api_documentation.html
http://www.javasoft.com/products/JDK/CurrentRelease/api/

Figure 42.4 : The handy, fully Web-based Java API manual is an indispensable programming resource.

Mandelbrot Set: An Introduction to Java Graphics

Fractals are an area of mathematics dealing with fractional dimensions. You probably recall from high school geometry that a line is a one-dimensional object, a square is two-dimensional, a cube is three-dimensional, and so forth. This all has to do with the traditional, comfortable world of Euclidean geometry, where two parallel lines never meet and the sum of the three angles in a triangle will always equal 180¡. Fractals deal with a whole other spectrum of dimensions, one in which a line might have a dimension not of 1, but of, say, 1.3756!

Around the turn of the century, mathematicians and philosophers began conceiving strange, abstract worlds where the common sense rules governing the Euclidean Universe were no longer true. The notion of fractional dimensions was conceived at that time, but it wasn't until well into the age of computers nearly 60 years later that it became practical to investigate the subject. The man who first applied computers to the subject, and who coined the term fractal, was Dr. Benoit Mandelbrot, of the IBM Research Labs.

Although fractals have proven themselves to be of practical value in everything from CGI special effects in Hollywood movies to fabulously efficient digital image compression techniques, we're interested in one kind of fractal-a Mandelbrot Set-for the following reasons:

If you want to learn more about fractals, check out any of the following:

Chaos: Making a New Science, by James Gleick (Viking Penguin, 1987)
The Spanky Fractal Database, http://spanky.triumf.ca/www/whats-new.html
Beauty of Fractals: Images of Complex Dynamical Systems, by H.O. Peitgen & P.H. Richter (Springer Verlag, 1986)

Mandelbrot Set Class Diagram

Figure 42.5 shows the preliminary design for your Mandelbrot program's class structure.

Figure 42.5 : Mandelbrot Set Class diagram.

You may have noticed that this class diagram shown in Figure 42.5 is almost identical to Figure 42.3, the class diagram for our HelloWorld example. It consists only of an applet (an execution context for our program to exist in), a canvas (to render graphics to), and one new class (a color map), so that we draw in more than just black and white. Note, too, that we developed our class diagram (however rudimentary) before we started coding.

Following is our sample Demo.bat (see Listing 42.4), Example.html (see Listing 42.5), and Mandel1.java (see Listing 42.6)source files. These, too, are very similar to the ones in our earlier HelloWorld applet.


Listing 42.4  Demo.bat-Windows Batch File for Compiling and Running the Mandelbrot Set
@rem Compile and execute sample program
javac Mandel1.java
appletviewer example.html


Listing 42.5  Example.html-HTML Web Page that Calls the Mandelbrot Applet
example.html
<HTML>
<TITLE>Mandelbrot Set</TITLE>
<BODY>
<APPLET CODE="Mandel1.class" WIDTH=425 HEIGHT=425>
If you can read this, then your browser is not set up for Java...
</APPLET>
<HR>
<A HREF="Mandel1.java">The source.</A>
</BODY>
</HTML>


Listing 42.6  Mandel1.java-First Version of Mandelbrot Program
/**
 * Mandel1: Plots Mandelbrot set and displays in Web Browser
 *
 * @version 1.0, DATE: 8.17.96
 * @author Paul Santa Maria
 */
import java.applet.*;
import java.awt.*;              // User Interface components

//
// MandelPlot: Implements Mandelbrot plot
//
class MandelPlot extends Canvas
{
  private int maxcol = 399, maxrow = 399, max_colors = 8,
        max_iterations = 512, max_size = 4;
  private Color cmap[];

  private void plot (Graphics g, int x, int y, int color_index)
  {
    g.setColor (cmap[color_index]);
    g.drawLine (x,y, x,y);
  }

  // MandelPlot display image constructor
  public MandelPlot ()
  {
     cmap = new Color[max_colors];

     cmap[0] = Color.black;
     cmap[1] = Color.red;
     cmap[2] = Color.green;
     cmap[3] = Color.blue;
     cmap[4] = Color.cyan;
     cmap[5] = Color.magenta;
     cmap[6] = Color.yellow;
     cmap[7] = Color.white;
  }

  // paint: actually draws the Mandelbrot set
  public void paint (Graphics g)
  {

     float Q[] = new float[400];
     double Pmax = 1.75,Pmin = -1.75, Qmax = 1.5, Qmin = -1.5,
        P, deltaP, deltaQ, X, Y, Xsquare, Ysquare;
     int color, row, col;

     deltaP = (Pmax - Pmin)/(double)(maxcol - 1);
     deltaQ = (Qmax - Qmin)/(double)(maxrow - 1);
     for (row=0; row<=maxrow; row++) {
       Q[row] = (float)(Qmin + row*deltaQ);
     }
     for (col=0; col<=maxcol; col++) {
       P = Pmin + col*deltaP;
       for (row=0; row<=maxrow; row++) {
         X = Y = 0.0;
         color = 0;
         for (color=0; color<max_iterations; color++) {
           Xsquare = X*X;
           Ysquare = Y*Y;
           if ((Xsquare+Ysquare) > max_size)
             break;
           Y = 2*X*Y+Q[row];
           X = Xsquare-Ysquare+P;
         }
         plot (g, col, row, (int)(color % max_colors));
       }
     }
  }
}

//
// Mandel1: sample program "main"
//
public class Mandel1 extends Applet
{
  private MandelPlot canvas;

  // Mandel: Frame constructor
  public void init ()
  {
     setLayout (new BorderLayout());
     canvas = new MandelPlot ();
     add ("Center", canvas);
   }

  // handleEvent: give us a way to gracefully exit the program
  public boolean handleEvent (Event evt)
  { if (evt.id == Event.WINDOW_DESTROY)
        System.exit (0);
     return false;
  }
}

Run Demo.bat to compile and link this program, and you should see the resulting image, as shown in Figure 42.6.

Figure 42.6 : This is just one of an infinite of number regions you could have plotted from the Mandelbrot Set.

Java AWT and Application Frameworks

Believe it or not, the structural similarity between our first two example programs (HelloWorld and Mandel1) is more than just coincidence. It gives us an important clue as to how tools such as Microsoft's AppWizard or Borland's AppExpert work and, more generally, why object-oriented programming has become so popular.

When you design your own programs, you need to figure out what kinds of things your program will be using, and then encapsulate the essential behavior of each into its own class.

Library designers do the same kind of thing, only at a higher level. What the designers of Java have done is they figured out what kinds of building blocks application developers might typically need, then assembled these into a general-purpose application framework. Ideally, an application framework lets you write entire applications almost on demand, with only minimal tailoring.

In Java, the application framework is called the Abstract Windows Kit (AWT). AWT is really very similar in spirit to Windows programming frameworks such as Microsoft's Foundation Classes (MFC) and Borland's Object Windows Library (OWL).

Both Microsoft and Borland bundle their respective application frameworks with their compilers, and supply sophisticated tools that make it possible to generate tailored programs with a simple point-and-click graphical interface. There are already tools from Symantec, Rogue Wave, BlueStone, IBM, and SunSoft that match, or surpass this level of functionality for Java programmers.

Optimizing the Mandelbrot Set Program

When you run this program, the first thing you may notice is that it's slow. It can take upwards of five to 10 minutes to plot on a Pentium-class machine (never mind the fact that the same code could have taken overnight on an old AT-class machine!).

Table 42.6 is a comparison of the same basic Mandelbrot program, run on exactly the same PC, compiled in different ways.

Table 42.6  Execution Time by Platform

Platform
Average Time
Standard Deviation
Native MS-Windows (Non-Java)
0:43
0.557
Java App (Windows 95)
2:55
1.89
Java Applet (Windows 95/Applet Viewer)
2:59
1.89
Java Applet (Windows 95/Netscape)
4:19
8.386

So do we have to live with this? Or can we somehow improve our program's performance? The answer to the second question is, "Yes: We can speed things up. Perhaps by a lot!"

Although it is expected that increasingly sophisticated development tools and just-in-time runtime optimizers will soon allow Java programs running within a Java virtual machine to run almost as fast as native executables, we cannot afford to wait for them. Fortunately, there is a great deal we can do ourselves-today-in terms of manually tuning performance.

But to optimize our code, we first need to understand exactly what it's doing, and how long it is taking each step of the way. We'll address this issue in the following two ways:

StopWatch: A Benchmarking Tool

How long does MandelPlot take to run on your PC? You can pull out a stopwatch and time it yourself, but that could get really boring really fast. Why not write a program to do it? Let's call this hypothetical program StopWatch. And let's make it general enough that we can reuse it in future programs that we might want to benchmark.

Introduction to State Transition Diagrams

To use a stopwatch, you click once to start timing, then click it again when you want to stop. You can click yet again if you want to resume timing. The watch always shows you the elapsed time since you started. Additionally, you can click another button to reset back to 0:00.

The concept is very simple, but coding it can be tricky. The problem is that it can be difficult to keep track of which operation is legal when. What happens if you resume before you hit start? Or pause after you've already stopped? Unless you keep careful track of all these subtle rules, it's all too easy to write a buggy program.

We can quickly and easily capture the semantics of a class such as StopWatch with a State Transition diagram, as shown in Figure 42.7.

Figure 42.7 : State Transition diagrams can be a useful design tool for any class that exhibits event-ordered behavior.

The circles represent each state our class can be in at any given moment: stopped, started, or paused. The lines show all of the legal transitions from one state into another.

Compare this State Transition diagram with the code for the class methods start(), stop(), pause(), and resume() in the Listing 42.7. As you can see, the source code practically falls right out of the state diagram! With any class that exhibits significant event-ordered behavior, sketching out a State Transition diagram can really simplify your work by suggesting a straightforward, simple design.


Listing 42.7  StopWatch.java-Implements Timing Functions
import java.util.*;     // Date, etc.

/**
 * StopWatch: Implements timing functions<p>
 *
 * <pre>SAMPLE USAGE:
 *   StopWatch t = new StopWatch ();
 *   t.start ();
 *   ...
 *   t.stop ();
 *   System.out.println ("elapsed time: "
 *     + t.getHH () + ", " + t.getMM () + ", " + t.getSS () );</pre>
 *   
 * @version 1.1, DATE: 8.17.96
 * @author Paul Santa Maria
 */
public class StopWatch
{

  public final static int STOPPED  = 0;
  public final static int RUNNING = 1;
  public final static int PAUSED  = 2;
  private int hh1, mm1, ss1;
  private int hh2, mm2, ss2;
  private int ehh, emm, ess;
  private int current_state;

 /*
  * store t1
  */
  private final void getStartTime ()
  {
    Date d = new Date ();
    hh1 = d.getHours ();
    mm1 = d.getMinutes ();
    ss1 = d.getSeconds ();
  }

 /*
  * store t2
  */
  private final void getCurrentTime ()
  {
    Date d = new Date ();
    hh2 = d.getHours ();
    mm2 = d.getMinutes ();
    ss2 = d.getSeconds ();
  }

 /*
  * compute (HH:MM:SS) ((t2-t1)+elapsed)
  */
  private final boolean computeElapsed ()
  {
    int hh, mm, ss;

    
    //Check if we've already computed elapsed time
    if (current_state == STOPPED || current_state == PAUSED) {
      return true;
    }
    
    getCurrentTime ();
    
    // Compute seconds
    if (ss2 < ss1) {
      ess += (60 + ss2) - ss1;
      mm2 -= 1;
    }
    else
      ess += ss2 - ss1;
    // Compute minutes
    if (mm2 < mm1) {
      emm += (60 + mm2) - mm1;
      hh2 -= 1;
    }
    else
      emm += mm2 - mm1;
    // Compute hours
    ehh = hh2 - hh1;

    // Now translate straight decimal to 60:60
    if (ess >= 60) {
      emm += 1;
      ess -= 60;
    }
    if (emm >= 60) {
      ehh += 1;
      emm -= 60;
    }
        
    // start incrementing again from current time
    getStartTime ();
    
    // Done!
    return true;
  }

 /**
  * public constructor
  */
  public StopWatch ()
  {
    reset ();
    current_state = STOPPED;
  }

 /**
  * Start incrementing time
  */
  public void start ()
  {
    if (current_state == STOPPED) {
      reset ();
      current_state = RUNNING;
    }
  }

 /**
  * Stop incrementing time
  */
  public void stop ()
  {
    if (current_state == RUNNING) {
      getCurrentTime ();
      computeElapsed ();
    }
    current_state = STOPPED;
  }

 /**
  * Clears elapsed time, re-initializes start time
  */
  public void reset ()
  {
    ehh = emm = ess = 0;
    getStartTime ();
  }


 /**
  * Stop incrementing time (until next start)
  */
  public void pause ()
  {
    if (current_state == RUNNING) {
      getCurrentTime ();
      computeElapsed ();
      current_state = PAUSED;
    }
  }

 /**
  * Resume incrementing time (until next pause)
  */
  public void resume ()
  {
    if (current_state == PAUSED) {
      getStartTime ();
      current_state = RUNNING;
    }
  }

 /**
  * Returns elapsed HH
  */
  public int getHH ()
  {
    if (computeElapsed ())
      return ehh;
    else
      return 0;
  }

 /**
  * Returns elapsed MM
  */
  public int getMM ()
  {
    if (computeElapsed ())
      return emm;
    else
      return 0;
  }

 /**
  * Returns elapsed SS
  */
  public int getSS ()
  {
    if (computeElapsed ())
      return ess;
    else
      return 0;
  }

 /**
  * Return stopwatch state
  */
  public int getState ()
  {
    return current_state;
  }
}

Coding a Test Driver: TestStopWatch

Being good programmers, we always create a test driver for any substantial new piece of software. Right?

Because it's slightly simpler, let's write TestStopWatch as a stand-alone application instead of a Java applet. We'll have more to say about how easy it is to switch back and forth between Java applets and stand-alone Java programs (and why one would ever want to do so!) in a few moments.

Basically, all we want to do is check out all the public interfaces to our new StopWatch class, see the results, and make sure everything works as we expect it to.

Complete source code for TestStopWatch.java is shown in Listing 42.8.


Listing 42.8  TestStopWatch.java-A Test Harness for StopWatch
import java.awt.*;      // GUI components

/**
 * TestStopWatch: Test harness for our StopWatch utility class
 *   
 * @version 1.1, DATE: 8.18.96
 * @author Paul Santa Maria
 */
public class TestStopWatch extends Frame
  implements Runnable
{

  public TestStopWatch ()
  {

    // Set Window title (would happen automatically if this were an
    // applet instead of a frame)
    setTitle ("TestStopWatch");

    // Create a "panel" to hold our clock time
    Panel p1 = new Panel ();
    p1.setLayout (new FlowLayout ());
    p1.add (new Label ("Elapsed HH:MM:SS "));
    timeHH = new TextField ("00", 3);
    p1.add (timeHH);
    timeMM = new TextField ("00", 3);
    p1.add (timeMM);
    timeSS = new TextField ("00", 3);
    p1.add (timeSS);
    add ("North", p1);

   // Now create another "panel" to contain our pushbuttons
    Panel p2 = new Panel ();
    p2.setLayout (new FlowLayout ());
    p2.add (new Button ("Start"));
    p2.add (new Button ("Stop"));
    p2.add (new Button ("Pause"));
    p2.add (new Button ("Resume"));
    p2.add (new Button ("Reset"));
    p2.add (new Button ("Quit"));
    add ("South", p2);

    // Create a sample StopWatch
    sw = new StopWatch ();

    // Finally, create a timer thread
    runner = new Thread (this);
    runner.start ();
  }

/*
 * handleEvent: process any window events (such as "close window")
 */
  public boolean handleEvent (Event evt)
  {
    if (evt.id == Event.WINDOW_DESTROY)
      do_quit ();
    return super.handleEvent (evt);
  }

/*
 * action: process any button clicks
 */
 public boolean action (Event evt, Object arg)
 {
    if (arg.equals ("Start")) {
      System.out.println ("Start");
      sw.start ();
    }
    else if (arg.equals ("Stop")) {
      System.out.println ("Stop");
      sw.stop ();
    }
    else if (arg.equals ("Pause")) {
      System.out.println ("Pause");
      sw.pause ();
    }
    else if (arg.equals ("Resume")) {
      System.out.println ("Resume");
      sw.resume ();
    }
    else if (arg.equals ("Reset")) {
      System.out.println ("Reset");
      sw.reset ();
    }
    else if (arg.equals ("Quit")) {
      System.out.println ("Quit");
      do_quit ();
    }
    else {
      System.out.println ("UNKNOWN EVENT");
      return false;
    }
    // "true" means we handled this event.
    // We shouldn't have any events besides button-pushes.
    return true;
  }

/*
 * "private" class data
 */
  private StopWatch sw;
  private TextField timeHH, timeMM, timeSS;
  private Thread runner;

/*
 * do_quit: exit (somewhat gracelessly, but very conveniently!
 */
  private void do_quit ()
  {
    // Terminate thread
    runner.stop ();
    // Abort the program & return to host OS
    System.exit (0);
  }

/*
 * main
 */
  public static void main (String[] args)
  {
    // Note: all this would happen automatically if
    //       this were an applet instead of a frame
    Frame f = new TestStopWatch ();
    f.resize (350, 100);
    f.show ();
  }

 /*
  * run: implement asynchronous timing loop
  */
  public void run ()
  {
    // The AWT interface for run () REQUIRES that we provide
    // an exception handler like this try .. catch
    try {
      // Loop forever
      for ( ;; ) {
        // Note strange syntax for converting int to String
        timeHH.setText ( "" + sw.getHH () );
        timeMM.setText ( "" + sw.getMM () );
        timeSS.setText ( "" + sw.getSS () );
        // Wait 1000 ms (1 second) for continuing loop
        Thread.sleep (1000);
      }
    }
    catch (InterruptedException e) {
    }
  }
}

Figure 42.8 shows what our TestStopWatch driver program looks like.

Figure 42.8 : It's always a good idea to write a test driver for any general-purpose class.


TIP
Debugging Java applets can present special challenges. When C++ or Basic programs fail, they usually GPF, dump core, or do something equally exciting. However, when an applet fails, it fails quietly
If your applet doesn't seem to be doing anything, you could be facing one of two problems:
  1. Your browser isn't running Java
  2. Your Java program isn't working correctly
You can eliminate the first possibility by seeing if any other Java applets run on your browser. If other applets run, then try recompiling your own applet. Double-check everything along the way: compiler errors, warning messages, spelling and capitalization, and so on.
If you suspect the problem is occurring inside your applet, you can step through your Java debugger or embed temporary printf statements (either System.out.println () or g.drawText ()) at strategic points in your source code.

A Closer Look at TestStopWatch

Although TestStopWatch is basically just a "quick hack" to test our StopWatch class, there are several interesting aspects of this program that bear closer scrutiny.

Compiling and Running a Java Application  TestStopWatch was our first exposure to a stand-alone Java application versus a Java applet.

You may notice that although we compiled the same way (javac myProgram.java), we ran it using Java instead of appletviewer or a Web browser. Listing 42.9 shows a new Demo.bat for compiling TestStopWatch.


Listing 42.9  Demo.bat-Compile and Run TestStopWatch Program
javac StopWatch.java
javac TestStopWatch.java
java TestStopWatch

Inheriting Main Class from Frame Versus Applet  Whereas Java applets must inherit from base class Applet, stand-alone Java applications usually inherit from base class Frame. Here is a sample comparison between an applet's base class (see Listing 42.10) and an application's base class (see Listing 42.11):


Listing 42.10  HelloWorld.java-Example Snippet from HelloWorld Applet
// This is how we typically set up the main class in a Java Applet:
public class HelloWorldApplet extends Applet
{
  public void init ()
  {
     setLayout (new BorderLayout ());
     ...


Listing 42.11  AnyProgram.java-Example Snippet from Hypothetical Java Stand-Alone Application
// This is how we typically set up the main class in a Java Application:
public class HelloWorldApplication extends Frame
{
  public static void main (String[] args)
  {
    Frame f = new myProgramFrame ();
    f.resize (100, 100);
    f.show ();
     ...

main() Method  The main class in any stand-alone Java application must have a method called public static void main (String[] args).

If you forget to do this (or if you accidentally mistype any part of its declaration), your Java program will fail to run.

Some Basic Java GUI Controls  TestStopWatch introduces us to our first GUI objects (known as widgets to X Windows programmers or controls to Windows programmers): pushbuttons, text edit controls, and text Labels.

Unlike Windows, where you typically declare controls in a separate resource file, Java lets you simply create them and use them on the fly. This is shown in Listing 42.12.


Listing 42.12  AnyProgram.java-Example Snippet Showing How to Arrange GUI Elements on a Java Panel
// Hey, kids!  Let's make some pushbuttons!
Panel p = new Panel ();
p.setLayout (new FlowLayout ());
p.add (new Button ("Start"));
p.add (new Button ("Quit"));
add ("South", p);

Panel Versus Canvas: Automatic Layout Management in Java  X Windows programmers are accustomed to relying on so-called container widgets to manage the layouts of their various GUI controls as they appear to the end-user. Windows programmers, on the other hand, must usually hard-code specific x- and y-coordinates for the height, width, and position for their controls.

Java more or less parallels the X Windows model by providing containers to manage the nitty-gritty details of positioning GUI controls for you.

Our TestStopWatch program uses two panels: p1 manages the Elapsed HH:MM:SS data on the top of our frame; p2 manages all of the pushbuttons on a single row at the bottom.

Our Frame (TestStopWatch) contains the panels. The panels, in turn, contain our GUI controls.

Automatic Event Management in Java  You were probably relieved to notice that event management was reasonably straightforward: you just declared the object and checked for any interesting events in your handleEvent() method!

Introduction to Java Threads  TestStopWatch also introduced us to Java's multithreading capabilities.

If TestStopWatch were written as a traditional, single-threaded C program, we would probably just fall into a simple do...while loop. We can't do that in Java, however, because if the program were trapped in a loop, it would never get a chance to handle any button-press events from the user.

If, on the other hand, TestStopWatch were written as a Windows or a Motif program, we would probably set up some kind of timer that would periodically pass some special timer event into our main event loop. Java neither has such a timer type nor a main event loop that we need to slavishly adhere to.

Instead, Java offers us what's arguably a much simpler, cleaner solution-we can just create a thread object that will be its own simple, self-contained do...while loop. Because it will run in parallel to the main program, we won't lock ourselves out of fielding any important user events. Listing 42.13 shows how it works.


Listing 42.13  TestStopWatch.java-Example Snippets Showing How to Implement a Timer Using Java Threads
// Declare that our class will be using threads:
public class TestStopWatch extends Frame
  implements Runnable

// Store the Thread object as private class data:
  private StopWatch sw;
  private TextField timeHH, timeMM, timeSS;
  private Thread runner;

// Create the thread in the main classes constructor:
  public TestStopWatch () {
    runner = new Thread (this);
    runner.start ();

// Destroy the thread when you quit the program:
  private void do_quit () {
    runner.stop ();

// Put your own code in a customized run() method
public void run () {
    try {
      // Loop forever
      for ( ;; ) {
        ...
      }
    }
    catch (InterruptedException e) {}
  }

Converting Java Types to "String"  As we mentioned earlier, Java is a strongly typed language. Our StopWatch class keeps track of time (hours, minutes, and seconds) with integers (type int).

But we need to convert this "time" data from int to String before we can display it. How do we do this? It's easy! Listing 42.14 shows one way.


Listing 42.14  TestStopWatch.java-Example Snippet Showing One Method of Converting a Java Primitive Type into a Java String
for ( ;; ) {
  timeHH.setText ( "" + sw.getHH () );
  timeMM.setText ( "" + sw.getMM () );
  timeSS.setText ( "" + sw.getSS () );

The magic here is that whenever you concatenate (using the + operator) a String with some value that isn't a String, Java will automatically convert the result into a String.

Here's a convenient way to put simple, C-like printf statements into Java applications:

System.out.println ("Myvalue: " + myInt)

Inter-Converting Applets and Stand-Alone Applications: A Cookbook

As you've seen from our TestStopWatch example, it's often easier to write and work with a stand-alone Java application than it is a Java applet. You don't have to deal with the hassle of setting up an HTML page, nor do you have the extra overhead of running from a Web page. More significantly, it's easier to debug your program using printf() trace statements (excuse me, System.out.println() trace statements!) from an application. Finally (and this brings us back full-circle to the topic we started with), you must run in standard application mode if you want to profile your application.

Fortunately, going back and forth between Java applications and Java applets is not at all difficult. After you have a working Java application, just do the following to convert it into an applet:

  1. Make an HTML page (we've been using Example.html) with an <APPLET> tag.
  2. Import java.applet.*.
  3. Derive from Applet, not Frame.
  4. Eliminate main().
  5. Write init().
  6. Rework border layout code.
  7. Eliminate setTitle().

Benchmarking and Profiling the Mandelbrot Set

Now that we've gone through all this hard work to implement a StopWatch function, let's use it to get a rough benchmark of our Mandelbrot program. Let's also use our newfound knowledge about inter-converting Java applications to turn the Mandelbrot program from an applet into an application-at least long enough to profile and optimize it. Finally, let's also run the profiler and get detailed statistical data.

TIP
Neither our StopWatch nor the Java profiler seriously affects runtime performance. The Heisenberg Uncertainty Principle does not apply here-you can safely measure our program without altering its behavior

Preparing Mandel2 for Profiling

Let's copy our baseline code into a new directory and make the following changes:

  1. Compile as before, using javac, but run java instead of appletviewer (see Listing 42.15).

Listing 42.15  Demo.bat-Windows Batch File for Compiling StopWatch, Mandelbrot Set, and Running with Profiling ON
@rem Compile and execute sample program
javac StopWatch.java
javac Mandel2.java
java -prof Mandel2

  1. Delete import java.applet.*; (be sure to keep import java.awt.*;).
  2. Globally substitute the new class name Mandel2. Inherit from Frame, not Applet.
    public class Mandel2 extends Frame {
  3. Throw away the applet's init() method and substitute an appropriate constructor method (see Listing 42.16).

Listing 42.16  Mandel2.java-Change Applet's init() Method into a Constructor Method
  // Mandel: Frame constructor
  public Mandel2 () {
     setTitle ("Mandelbrot Set: Version 2");
     canvas = new MandelPlot ();
     add ("Center", canvas);
  }

  1. Write a main() method. Create a frame and write associated layout code (see Listing 42.17).

Listing 42.17  Mandel2.java-main() Method: Required for Any Stand-Alone Java Application
  // main: create frame, display Mandelbrot set
  public static void main (String args[]) 
     Frame f = new Mandel2 ();
     f.resize (400, 400);
     f.show ();
  }

  1. Add our StopWatch inside the paint() method to compute elapsed time (see Listing 42.18).

Listing 42.18  Mandel2.java-Add StopWatch to the Mandelbrot Set Program to Show Elapsed Time
  // paint: actually draws the Mandelbrot set
  public void paint (Graphics g)
...
     StopWatch timer = new StopWatch ();
      timer.start ();
...
     timer.stop ();
     g.setColor (Color.black);
     g.drawString ("hh: " + timer.getHH ()
       + ", mm: " + timer.getMM ()
       + ", ss: " + timer.getSS (),
       0, 16);
   ...

  1. Try it out!

Figure 42.9 shows the result of our revised Mandelbrot set, with timing information printed out in the upper-left corner (2 minutes and 54 seconds).
Figure 42.9 : The Mandelbrot Set with timing information (2:54) printed out.


CAUTION
Because we put our plot Mandelbrot set code inside of the paint() method, the image will be recomputed and redrawn anytime anything happens to the canvas area. For this reason, you might want to turn off screensavers and not open or move windows over the canvas area when you run this program. There are several advanced techniques that can get around this problem, such as using buffered images. A complete discussion of these techniques-and their relative pros and cons-is outside the scope of this chapter

Using Java's Profiler

As we can see from StopWatch, it took 2 minutes, 54 seconds to plot the Mandelbrot Set.

TIP
It is worth noting that this Java stand-alone application runs nearly twice as fast as the same code run as an applet from inside the Netscape 2.0 browser. This will become less of a problem as more Web browsers incorporate Just In Time compilers, which can make Java applications run nearly as fast as native executables. But speed and performance issues are clearly something to keep in mind if you're planning any especially ambitious Java applets

Because we used the -prof command-line switch, Java created a java.prof execution profile in our working directory. Listing 42.19 shows a few snippets from the execution profile of Mandel2.java.


Listing 42.19  java.prof-Execution Profile of Mandel2 Program
# count callee caller time
1 java/awt/Component.getBackground()Ljava/awt/Color; 
java/awt/Component.getBackground()Ljava/awt/Color; 0
3 java/awt/Component.getFont()Ljava/awt/Font; 
java/awt/Component.getFont()Ljava/awt/Font; 0
3 java/awt/Component.postEvent(Ljava/awt/Event;)Z 
java/awt/Component.postEvent(Ljava/awt/Event;)Z 0
3 java/lang/Object.<init>()V java/lang/String.<init>(Ljava/lang/
StringBuffer;)V 0
92 java/lang/Object.<init>()V java/lang/String.<init>([C)V 0
...
160000 sun/awt/win32/Win32Graphics.drawLine(IIII)V 
MandelPlot.plot(Ljava/awt/Graphics;III)V 18389
160000 sun/awt/win32/Win32Graphics.setColor(Ljava/awt/Color;)V MandelPlot.plot(Ljava/awt/Graphics;III)V 3150
11604 sun/awt/win32/Win32Graphics.pSetForeground(Ljava/awt/Color;)V 
sun/awt/win32/Win32Graphics.setColor(Ljava/awt/Color;)V 2486
160000 MandelPlot.plot(Ljava/awt/Graphics;III)V MandelPlot.paint(Ljava/awt/Graphics;)V 24341
1 MandelPlot.paint(Ljava/awt/Graphics;)V 
sun/awt/win32/MComponentPeer.paint(Ljava/awt/Graphics;)V 174850
1 sun/awt/win32/MComponentPeer.handleExpose(IIII)V ?.? 174896
...

As you can see, the raw data generated by the profiler is not exactly user-friendly. Nevertheless, it's a useful tool and the information it yields is important for us to understand.

The profiler keeps track of every Java method that's called. It logs the following into java.prof:

We'll analyze this raw data to learn the following:

Table 42.7 shows the most time-consuming routines from java.prof, sorted by time. These, clearly, are the most likely candidates for optimization.

Table 42.7  Mandel2 Execution Profile (Before Optimization) "Baseline version": 2:54

# countcallee callertime
11604pSetForegroundsetColor 2486
160000setColorplot 3150
160000drawLineplot 18389
160000plotpaint 24341
1MandelPlot.paintMComponentPeer.paint 174850
1handleExpose?.? 174896

Okay, so what does all of this mean? The following are a couple of observations:

How Do You Optimize Your Java Program?

Here are a couple of guidelines for optimizing Java programs. All of these suggestions are equally applicable to Java applets as well as Java applications.

General optimization guidelines:

// Poor: the same value is computed and assigned twice
j = 2 + 2; i = j; i = 2 + 2;
// Better
i = 4;

How Did We Optimize the Mandelbrot Set?

After studying java.prof, we're ready to hand-tune our Mandelbrot Set. We will not change the basic design. We merely want to target and rewrite those specific parts of the program that seem to be hogs.

Here are specific changes that we made to our final version, Mandel3.java. As you study the program yourself, you will undoubtedly discover other, perhaps better, changes that could be made:

These modifications are shown in Listing 42.20.


Listing 42.20  Mandel3.java-Snippets Showing the Optimizations to our Mandelbrot Program
class MandelPlot extends Canvas
{
  private static final int maxcol = 399, maxrow = 399, max_colors = 8,
        max_iterations = 512, max_size = 4;
  private static Color cmap[];

// Reduce #/setColor and #/drawLine graphics I/O calls 
  private static Color last_color = Color.black;
  private static int last_x = -1, last_y = -1;
  private static Graphics graphics_context;

  private static final void plot (int x, int y, int color_index)
  {
    // See if we've moved to a different column
    if (x != last_x) {
      if (last_x >= 0) {
        graphics_context.drawLine (last_x, last_y, last_x, 399);
        last_y = y;
      }
      last_x = x;
      last_color = cmap[color_index];
      graphics_context.setColor(last_color);
    }
    else {
      if (cmap[color_index] != last_color) {
        graphics_context.drawLine (last_x, last_y, last_x, y-1);
        last_y = y;
        last_color = cmap[color_index];
        graphics_context.setColor (last_color);
      }
    }
  }
...
// Avoid the overhead of unnecessary redraw
  public final void update (Graphics g)
  {
    paint (g);
  }
...
// Save a few cycles/plot by assigning g here, as a a global
  public final void paint (Graphics g)
    ...
    graphics_context = g;
    ...

As you can see in Figures 42.10 and 42.11, there is a considerable improvement in execution time.

Figure 42.10 : The optimized Java application runs considerably faster (2:28).

Figure 42.11 : Java applets show similar improvement after optimization!

Table 42.8 shows the java.prof execution profile of our optimized Mandelbrot Set program. Compare this with the unoptimized version shown earlier in Table 42.7.

Table 42.8  Mandel3 Execution Profile (After Optimization) "Optimized": 2:32

# countcallee caller
time
11604pSetForegroundsetColor
2547
11996setColorplot
2761
11995drawLineplot
4001
160000plotpaint
7957

"Gotcha's" and Common Misperceptions

Over the course of the past several pages, we've learned the basic mechanics of writing Java applets. Although we've hardly scratched the surface of everything Java is capable of doing for you and your development team, we sincerely hope that you're excited about what you've seen so far.

Unfortunately, nothing is perfect. Not even for a programming language as cool as Java! Let's talk for a few moments about some of the problems a Java programmer might encounter:

With all the hype surrounding Java, there's sometimes a tendency to view Java as a "one-stop solution" to all active content on the Web. This is simply not the case: Java inter-operates well with many other Internet technologies. For example,

Other Resources

Congratulations! You are now a Java applet developer! Well-armed with solid experience, a grasp of the syntactic basics and main programming concepts, and an appreciation for good design habits, you should now be prepared to start developing your own applets and full-blown Web-based applications.

Where do you go from here? Probably the best place to start is to glance around at some of the exciting things your fellow developers around the world are doing with Java. Here are a couple of popular URLs to get you started. Above all, enjoy!

ON THE WEB
http://www.javasoft.com  Sun's official site for the latest information about the Java language
http://www.gamelan.com  Arguably the largest and most popular "unofficial" site for the Java programming community. A great site to learn about Java tools, discover other Java-related home pages, and find sample code.
news:comp.lang.java  Probably the best way to ask and answer Java-related questions from the worldwide Java programming community.