Various


Applets and Applications

La differenza tra un Applet e' una Applicazione e' data dalla differente dichiarazione della classe principale.
Nel caso di un Applet, si prevede che sia attivato all'interno di un browser del linguaggio html, come tale necessita della seguente dichiarativa:
public class XXX extends Applet
{
  public void init() {
    ...
  }
}

La prima riga indichera' al browser che la classe dovra' ereditare le caratteristiche della classe Applet.
Nel caso di una Applicazione deve esistere il metodo main perche' la JVM sappia come attivare l'istanza del programma:
public class XXX
{
  public static void main( String args[] ) {
    xxx  =  new XXX();
    ...
  }
}

Examples

public class XXX extends Applet
{
  static    XXX      xxx;
  GUI       gui;

  //----------------------------------------------------------------------------
  // main for start as applet
  public void init() {
    gui  =  new GUI();
  }

  //----------------------------------------------------------------------------
  // main for start as standalone application
  public static void main( String args[] ) {
    xxx  =  new XXX();
    xxx.init();
  }
}



Interfacing to an Applet

Suppose that we want to take the above calculator program and call it from an applet. How would we do this? Here's a simple example of an applet that will interface with the calculator code.
        import java.awt.*;

        public class applet extends java.applet.Applet {
                public void paint(Graphics g)
                {
                        String input_expr = getParameter("input_expr");
                        calc c = new calc(input_expr);
                        String out = c.get_value();
                        g.drawString("Input = " + input_expr, 25, 50);
                        g.drawString("Value = " + out, 25, 75);
                }
        }

This is similar to the applet illustrated in the last issue, save for the lines:
        String input_expr = getParameter("input_expr");
        calc c = new calc(input_expr);
        String out = c.get_value();

The last two of these we saw in the example above. The first line illustrates how one can get parameters passed to the applet from HTML code, kind of similar to command-line parameters. The corresponding HTML to run this applet would be:
        <html>
        <head>
        <title>Interface to Calculator Applet
        </title>
        </head>
        <body>

        <applet code="applet.class" width=150 height=150>
        <param name=input_expr value="1/2/3*4">
        </applet>

        </body>

        </html>

This HTML is similar to that illustrated in newsletter #001, save for the line:
        <param name=input_expr value="1/2/3*4">

which actually passes in the parameter value. When this applet is executed, the result will be something like:
        Input = 1/2/3*4
        Value = 0.666667


Button Input

In the last issue we presented a simple drawing applet, that tracks mouse input and draws on the screen accordingly. Suppose that we'd like to modify this applet so that the user can toggle between two different colors. How might we do this? One approach looks like so:
        import java.applet.*;
        import java.awt.*;

        public class draw extends Applet {

                int prev_x = 0;
                int prev_y = 0;
                boolean color = false;
                Button ccb;

                public void init()
                {
                        ccb = new Button("Toggle Color");
                        add(ccb);
                }

                public boolean action(Event e, Object o)
                {
                        if (e.target == ccb) {
                                color = !color;
                                return true;
                        }
                        else {
                                return false;
                        }
                }

                public boolean mouseDown(Event e, int x, int y)
                {
                        prev_x = x;
                        prev_y = y;

                        return true;
                }

                public boolean mouseDrag(Event e, int x, int y)
                {
                        Graphics g = getGraphics();

                        g.setColor(color == false ? Color.red : Color.blue);

                        g.drawLine(prev_x, prev_y, x, y);

                        prev_x = x;
                        prev_y = y;

                        return true;
                }
        }

using this HTML interface to the applet:
        <html>
        <head>
        <title>Interface to Text Applet
        </title>
        </head>
        <body>
        <applet code="draw.class" width=300 height=300>
        </applet>
        </body>
        </html>

This code is similar to the previous example, but we've added a button that has "Toggle Color" in it. The action() method is called in response to user events, and we check whether the user in fact clicked on the button. If so, we toggle the color state internally, and the color switches from red to blue or vice versa. If the event passed to action() is not a button click, then we pass it back to the parent to handle.

In the next issue we'll get into the area of text input, showing a low-level and a higher-level way of entering text.


Text Input

In the last issue we talked about button input, where the user clicks on a button. In this issue we'll continue our discussion of input and discuss text input a bit, starting with low-level character input. To illustrate what such input looks like, here is a simple applet:
        import java.applet.*;
        import java.awt.*;

        public class text1 extends Applet {

                int x = 40;
                int y = 40;

                public boolean keyUp(Event e, int key)
                {
                        if ((e.modifiers & Event.CTRL_MASK) != 0) {
                                char buf[] = new char[2];
                                buf[0] = '^';
                                key += 0x40;
                                buf[1] = (char)key;
                                getGraphics().drawChars(buf, 0, 2, x, y);
                                x += getFontMetrics(getFont()).charWidth('^');
                                x += getFontMetrics(getFont()).charWidth(key);
                                x += 2;
                        }
                        else {
                                char buf[] = new char[1];
                                buf[0] = (char)key;
                                getGraphics().drawChars(buf, 0, 1, x, y);
                                x += getFontMetrics(getFont()).charWidth(key);
                                x++;
                        }
                        return true;
                }
        }


and the HTML that drives it:
        <html>
        <head>
        <title>Interface to Text Applet</title>
        </head>
        <body>
        <applet code="text1.class" width=350 height=125></applet>
        </body>
        </html>

keyUp() is a method called in response to a keyboard event. Once inside keyUp(), we go through some machinations to determine what sort of a key was pressed, for example whether a control key was hit. The code in this example is incomplete but illustrative of the technique.

Once we have a key, we want to echo it in the applet window. We use drawChars() for this. Then we need to update the X position in the window for drawing the next character, and to do that, we use the FontMetrics class with the current font, to determine the width of a character that's just been drawn.

In other words, this applet simply echoes its input to the window, and throws in a "^" in front of control characters.

There are higher-level methods for entering text, which we will look at in future issues.


Text Fields

In the previous issue we showed how to use low-level character input within an applet. In this issue we'll discuss higher-level input using TextFields. Consider the following example, an applet that gathers name and address from a user and writes the data to a local file:
        import java.applet.*;
        import java.awt.*;
        import java.io.*;

        public class text4 extends Applet {

                TextField tf1;                  // text fields for address
                TextField tf2;
                TextField tf3;
                Button db;                      // Done button
                Label lb;                       // Label used as message
                Color bg = new Color(0xffffff); // background/foreground clrs
                Color fg = new Color(0x000000);

                public void init()
                {
                        // set colors

                        setForeground(fg);
                        setBackground(bg);

                        // create text fields

                        tf1 = new TextField(35);
                        tf2 = new TextField(35);
                        tf3 = new TextField(35);

                        // create button and label

                        db = new Button("Done");
                        lb = new Label();

                        // arrange items in window

                        setLayout(new GridLayout(4, 2, 10, 10));
                        add(new Label("Name:"));
                        add(tf1);
                        add(new Label("Address #1:"));
                        add(tf2);
                        add(new Label("Address #2:"));
                        add(tf3);
                        add(db);
                        add(lb);
                }

                private boolean write()
                {
                        // check input fields

                        if (tf1.getText() == null ||
                            tf1.getText().length() == 0)
                                return false;
                        if (tf2.getText() == null ||
                            tf2.getText().length() == 0)
                                return false;
                        if (tf3.getText() == null ||
                            tf3.getText().length() == 0)
                                return false;

                        // write out name and address to end of file

                        try {
                                RandomAccessFile raf = new
                                    RandomAccessFile("datafile", "rw");
                                raf.seek(raf.length());
                                raf.writeBytes(tf1.getText());
                                raf.writeByte('\n');
                                raf.writeBytes(tf2.getText());
                                raf.writeByte('\n');
                                raf.writeBytes(tf3.getText());
                                raf.writeByte('\n');
                                raf.writeByte('\n');
                                raf.close();
                        }
                        catch (Throwable e) {
                        }

                        return true;
                }

                public boolean action(Event e, Object o)
                {

                        // Done button selected

                        if (e.target == db) {
                                if (write())
                                        lb.setText("Written ...");
                                else
                                        lb.setText("Invalid field value");
                                return true;
                        }
                        else {
                                return false;
                        }
                }
        }

This applet uses the following HTML code to drive it:
        <html>
        <body bgcolor="#ffffff" text="#000000" link="#ff0000" vlink="#000000">
        <head>
        <title>Interface to Text Applet</title>
        </head>
        <body>
        Please enter your name and address then select Done.
        <br>
        <br>
        <applet code="text4.class" width=350 height=125></applet>
        </body>
        </html>

In this example, we use the init() method of the applet to set the background and foreground colors, and then we create the individual items of the window. We use a layout manager for this purpose. A layout manager is a mechanism for arranging items in a window, or more precisely, Component objects in a Container. Applet is derived from Panel which is derived from Container. And an item like TextField is derived from TextComponent which is derived from Component.

So when we create text fields and buttons and so on, we are creating objects of classes derived from Component, and using a layout manager to arrange these objects in a Container object.

After we've set up the window items, we can then add some logic within the action() method to check whether the user selected the Done button, and if so, then we interrogate the text fields using getText() and extract the input data. Finally, we write this data to a file. We append to the end of the file by obtaining its length and positioning at the end of file.


Animation

In previous issues we've talked about the use of basic graphics in a Java applet, and considered some techniques for the input of text. In this issue we'll talk about something quite different, namely animation. This is a technique that can be used to make applets do "neat" things.

First of all, let's look at the source for an animation applet:
        import java.applet.*;
        import java.awt.*;

        public class Animate extends Applet implements Runnable {

                // thread identifier
                private Thread an_thread = null;

                // Start and Stop buttons
                private Button start_button = null;
                private Button stop_button = null;

                // current state of animation
                private int st = 0;

                // initialize the applet
                public void init()
                {
                        start_button = new Button("Start");
                        stop_button = new Button("Stop");
                        add(start_button);
                        add(stop_button);
                }

                // handle mouse actions
                public boolean action(Event e, Object arg)
                {
                        if (e.target == start_button) {
                                start();
                                return true;
                        }
                        else if (e.target == stop_button) {
                                stop();
                                return true;
                        }
                        else {
                                return super.action(e, arg);
                        }
                }

                // start the applet
                public void start()
                {
                        if (an_thread == null) {
                                an_thread = new Thread(this);
                                an_thread.start();
                        }
                }

                // stop the applet
                public void stop()
                {
                        if (an_thread != null && an_thread.isAlive())
                                an_thread.stop();
                        an_thread = null;
                        st = 3;
                }

                // run a thread
                public void run()
                {
                        for (;;) {

                                // get graphics for the applet window

                                Graphics g = this.getGraphics();
                                try {
                                        switch (st++) {

                                        case 0:
                                        g.setColor(Color.red);
                                        g.fillOval(25, 35, 250, 250);
                                        break;

                                        case 1:
                                        g.setColor(Color.yellow);
                                        g.fillOval(125, 135, 150, 150);
                                        break;

                                        case 2:
                                        g.setColor(Color.blue);
                                        g.fillOval(225, 235, 50, 50);
                                        break;

                                        case 3:
                                        g.clearRect(0, 0, 300, 300);
                                        st = 0;
                                        break;

                                        }

                                        // sleep for a second
                                        Thread.sleep(1000);
                                }

                                catch (InterruptedException e) {
                                }
		                        g.dispose();
                }
        }

along with the HTML code that drives the applet:
        <html>
        <head>
        <title>Interface to Animation Applet</title>
        </head>
        <body>
        <applet code="Animate.class" width=300 height=300></applet>
        </body>
        </html>

We've seen parts of the applet code before, for example the graphics that draws ovals (actually circles in this example), the init() method, the setting up of buttons, and so on. This particular animation draws three circles of different sizes and colors, and then repeats itself.

What's different in this example is the use of threads. A thread, which also is called names like "lightweight process" and "task", is a distinct execution of Java code that is taking place at a given time. A program or applet may use threads to allow multiple streams of code to execute simultaneously.

Normally a Java applet responds to events such as mouse clicks or keyboard input. But we'd like this animation applet to do something continuously without waiting for events, so we create a thread and start it running. The lines:
        an_thread = new Thread(this);
        an_thread.start();

create a thread, specifying a reference for a class object that implements the Runnable interface (that is, defines a method run()). This method is executed as the "body" of the thread. In the case at hand, the method simply checks the current state and draws the appropriate circle or else clears the window in preparation for starting another cycle.

We've set up a couple of Start and Stop buttons, tied to start() and stop() methods in the applet. If Stop is selected, the thread execution stops, and Start will restart the animation by reestablishing the thread.

Threads are an important part of Java about which we will say more in future issues.


Client/Server Example

In this issue we'll show a simple example of client/server programming. The client will be an applet and the server a regular Java program with a main() method in it.

In the client/server model, there is a server program running on some computer. It accepts connections from clients across the network, and serves each of them. For example, the client may be used to accept some input from a user, which is sent to the server and entered into a database. The server can also send information back to the client, such as an acknowledgment.

Server and client communicate via what is known as a socket. More technically, a socket is an endpoint of a communications channel, and thus there is a socket on each end of the channel, one socket for the server and one for the client.

Given a socket, it's possible to do conventional Java I/O between server and client.

Let's now look at the programs:
        // server.java

        import java.io.*;
        import java.net.*;

        public class server extends Thread {

                public static final int DEF_PORT = 1234;// port
                private int port;
                private ServerSocket listen;            // server socket

                public server()
                {
                        // set up the server socket port

                        port = DEF_PORT;
                        try {
                                listen = new ServerSocket(port);
                        }
                        catch (IOException e) {
                                System.err.println("socket creation error");
                                System.exit(1);
                        }

                        // start the server thread running

                        start();
                }

                public void run()
                {
                        try {
                                // accept connections and process them

                                for (;;) {
                                        Socket cs = listen.accept();
                                        connection c = new connection(cs);
                                }
                        }
                        catch (IOException e) {
                                System.err.println("connection error");
                        }
                }

                public static void main(String[] args)
                {
                        new server();
                }
        }

        class connection extends Thread {

                private Socket client;                  // client socket
                private DataInputStream in;             // input from socket
                private PrintStream out;                // output to socket

                public connection(Socket cs)
                {
                        // set up an individual connection

                        try {
                                client = cs;
                                InputStream is = client.getInputStream();
                                in = new DataInputStream(is);
                                OutputStream os = client.getOutputStream();
                                out = new PrintStream(os);
                        }
                        catch (IOException e) {
                                try {
                                        client.close();
                                }
                                catch (IOException ee) {
                                        System.err.println("close error");
                                }
                                System.err.println("socket stream error");

                                return;
                        }

                        // start it running
                        start();
                }

                public void run()
                {

                        // read from socket input and write back to output
                        try {
                                for (;;) {
                                        String ln = in.readLine();
                                        if (ln == null)
                                                break;
                                        if (ln.length() == 0)
                                                out.println("empty input");
                                        else
                                                out.println("OK: " + ln);
                                }
                        }
                        catch (IOException e) {
                                System.err.println("server I/O error");
                        }

                        // close connection

                        finally {
                                try {
                                        client.close();
                                }
                                catch (IOException ee) {
                                        System.err.println("close error");
                                }
                        }
                }
        }

        // client.java

        import java.applet.*;
        import java.awt.*;
        import java.io.*;
        import java.net.*;

        public class client extends Applet {

                public static final int DEF_PORT    = 1234;  // port
                Socket                  s;                   // socket
                DataInputStream         in;                  // socket input
                private PrintStream     out;                 // socket output
                TextField               input_field;         // input field
                TextArea                out_area;            // output display area

                public void init()
                {
                        try {
                                // set up socket
                                String host = getCodeBase().getHost();
                                s           = new Socket(host, DEF_PORT);
                                in          = new DataInputStream(s.getInputStream());
                                out         = new PrintStream(s.getOutputStream());

                                // set up window
                                input_field = new TextField();
                                out_area = new TextArea();
                                out_area.setEditable(false);
                                setLayout(new BorderLayout());
                                add("North", input_field);
                                add("Center", out_area);
                        }
                        catch (IOException e) {
                                System.err.println("exception during setup");
                        }
                }

                public boolean action(Event e, Object o)
                {
                        if (e.target == input_field) {

                                // we have some input from the user

                                try {

                                        // dump it to the server

                                        out.println((String)e.arg);
                                        input_field.setText("");

                                        // read response


                                        String status = in.readLine();
                                        out_area.setText(status);

                                        return true;
                                }
                                catch (IOException ee) {
                                        out_area.setText("server I/O error");
                                }
                        }
                        return false;
                }
        }

The server is compiled as usual and simply started as a Java program:
        $ java server

while the client is driven via some HTML:
        <html>
        <head>
        <title>Client Applet</title>
        </head>
        <body>
        <applet code="client.class" width=300 height=300></applet>
        </body>
        </html>

If you start the client without the server being present, it will give an error because of failure to connect to the server.

This particular server/client combination simply validates input from the client and sends back an acknowledgment. Each client connection runs as a separate thread, so that many clients can be served simultaneously without the need for polling.

Note that the server knows to close a given client connection (the client has gone away) by receipt of a "null" when reading input from that connection. By contrast, the server "never" goes away; it must be explicitly terminated by the user.

Note also that the socket port must be unique on the system running the server, and that the server and client must agree on port assignments.


Image Loading and Filtering

An interesting aspect of applet programming that we've not talked much about is the use of images. In this issue we'll present a simple example of how images are loaded and manipulated.

Let's first look at some actual applet code:
        // Filter.java
        import java.applet.*;
        import java.awt.*;
        import java.awt.image.*;

        public class Filter extends Applet {

                Image img;
                Image black;
                boolean flag = true;

                public void init()
                {
                        img = getImage(getDocumentBase(), "image.gif");
                        ImageFilter f = new BlackFilter();
                        ImageProducer ip = new FilteredImageSource(
                            img.getSource(), f);
                        black = createImage(ip);
                        repaint();
                }

                public void update(Graphics g)
                {
                        g.clearRect(0, 0, size().width, size().height);
                        g.drawImage(flag ? img : black, 10, 10, this);
                        flag = !flag;
                }

                public boolean mouseUp(Event e, int x, int y)
                {
                        repaint();
                        return true;
                }
        }

        class BlackFilter extends RGBImageFilter {

                public BlackFilter()
                {
                        canFilterIndexColorModel = true;
                }

                public int filterRGB(int x, int y, int rgb)
                {
        				int a = rgb & 0xff000000;
        				int r = (((rgb & 0xff0000) + 0xff0000) / 2) & 0xff0000;
        				int g = (((rgb & 0xff00) + 0xff00) / 2) & 0xff00;
        				int b = (((rgb & 0xff) + 0xff) / 2) & 0xff;
                        //return a | r | g | b;
                        return a | 0 | 0 | 0;
                }
        }

which is driven by HTML code:
        <html>
        <head>
        <title>Interface to Filter Applet</title>
        </head>
        <body>
        <applet code="Filter.class" width=300 height=300></applet>
        </body>
        </html>

"image.gif" is not supplied in this newsletter and you'll need to find your own image if you want to try this example.

This particular applet draws an image, and then toggles the image to black and back to its original color at each mouse click. The commented-out line of code at the bottom of the applet would instead "gray out" the image by averaging its RGB (red/green/blue) color values with white.

The applet is conventional in structure save for the image filtering and the color manipulation.

The image is retrieved using getImage(), specifying a name ("image.gif") and a URL document base. We then create a black filter and filter the loaded image through it. With image filtering, an ImageProducer is a source of an image. A filter can be applied to the ImageProducer, resulting in another ImageProducer from which an actual image can be created using createImage(). This is a bit of simplification of what the java.awt.image package is really about, but it's sufficient for our purposes.

The RGB transformation averages each color with white, if graying out is desired, or else simply returns 0 | 0 | 0 (black in the RGB color scheme). The high 8 bits (mask 0xff000000) represent the "alpha" value, used to represent transparency.

An example of another type of transformation on images would be CropImageFilter(), that crops an image to a specified rectangle.


Other


Size

Use javac -O. This inlines functions (which makes the bytecode bigger) and removes
            line numbers (which makes it smaller). Unless you use lots of inlinable functions, the
            removal of line numbers will dominate and your bytecode will get smaller. However, note
            that things can sometimes be inlined when they shouldn't -- see the compilers page for
            details.


Memory Usage

In issue #027 we looked at a new 1.2 feature, reference classes. These are used in areas such as caches and garbage collection, as an aid in managing memory.

Another such aid is memory usage advisement. This feature is used to inform an application about where it stands with its use of memory, for example whether it is close to exhausting memory. In such a case the application might for example choose to flush some of its caches, freeing up memory.

To see how this works, consider the following example:
        class Rec {
                double data1;
                double data2;
                double data3;
                double data4;
                double data5;
                double data6;
                double data7;
                double data8;
                double data9;
                double data10;
                Rec next;
        }

        public class mem {
                private static int last_adv = -1;

                public static void getmem()
                {
                        Runtime rt = Runtime.getRuntime();
                        int adv = rt.getMemoryAdvice();

                        if (adv == last_adv)
                                return;
                        last_adv = adv;

                        switch (adv) {
                                case Runtime.MemoryAdvice.GREEN:
                                        System.out.println("green");
                                        break;
                                case Runtime.MemoryAdvice.YELLOW:
                                        System.out.println("yellow");
                                        break;
                                case Runtime.MemoryAdvice.ORANGE:
                                        System.out.println("orange");
                                        break;
                                case Runtime.MemoryAdvice.RED:
                                        System.out.println("red");
                                        break;
                        }
                }

                public static void main(String args[])
                {
                        Runtime rt = Runtime.getRuntime();

                        Rec head = null;
                        for (;;) {
                                Rec r = new Rec();
                                r.next = head;
                                head = r;
                                getmem();
                        }
                }
        }

Rec is a data record of some type, and main() allocates a long linked list of these records. They cannot be garbage collected because all are active (head points at the first, the first points at the second, and so on).

At each iteration of the loop, getmem() is called to check the current status of memory. When the program is run using JDK 1.2 beta 3, output is:
        green
        orange
        red
        java.lang.OutOfMemoryError
                at java.io.FileOutputStream.write(Compiled Code)

The returned advice on memory goes through increasingly serious stages (green, yellow, orange, red), with the latter stages indicating that the application had better do something to free up some of its memory. Java uses garbage collection rather than explicit freeing of memory, and to free memory implies removing references from no-longer-used objects, so that the garbage collector can free them.


Exceptions as a control structure

Java supports the use of exceptions as an integral part of the language. When an invalid condition is detected, an exception is thrown, and later caught by an exception handler (or else the program aborts).

Exceptions can be used for more than error handling, however, and it's interesting to consider their use in improving performance (see also the March 1998 issue of Byte magazine for an article on this topic).

Suppose that you want to add up all the values of the elements in an array. One obvious, and one not-so-obvious, approach to doing this is as follows:
        public class test {
                public static int sum1(int vec[])
                {
                        int s = 0;
                        int len = vec.length;
                        for (int i = 0; i < len; i++)
                                s += vec[i];
                        return s;
                }

                public static int sum2(int vec[])
                {
                        int s = 0;
                        try {
                                for (int i = 0; ;i++)
                                        s += vec[i];
                        }
                        catch (ArrayIndexOutOfBoundsException e) {
                        }
                        return s;
                }

                public static void main(String args[])
                {
                        int x[] = new int[1000000];
                        long t = 0;

                        t = System.currentTimeMillis();
                        int s1 = 0;
                        for (int i = 1; i <= 10; i++)
                                s1 = sum1(x);
                        System.out.println(System.currentTimeMillis() - t);
                        System.out.println(s1);

                        t = System.currentTimeMillis();
                        int s2 = 0;
                        for (int i = 1; i <= 10; i++)
                                s2 = sum2(x);
                        System.out.println(System.currentTimeMillis() - t);
                        System.out.println(s2);
                }
        }

sum1() represents the obvious approach, while sum2() uses an exception to break out of the loop. Note that no loop ending condition is specified, because the Java language guarantees that array indices will be checked, with an exception thrown if an invalid one is found. Using JDK 1.1.3 without Just In Time compilation, the second method runs about 15% faster than the first.

This technique fits into the category of "clever" programming, of the sort that can make code hard to understand, and that relies on certain assumptions about how exceptions are implemented. Given this, it can't be recommended as a general technique. But it may be useful if you're desperate to improve performance, and it illustrates how exceptions are integrated into the Java language.


Native2ascii

In previous issues we've seen how Java programs are composed of ASCII characters, with \uxxxx used to represent Unicode escapes for native characters. Unicode escapes are translated in the first phase of Java compilation.

The JDK contains a small utility program that translates native character sets into ASCII and the reverse. For example, if I have in a file the line:
        \u0061b\u0063

and I say:
        $ native2ascii -reverse infile outfile

then the output file will have:
        abc

In other words, I converted an ASCII representation using Unicode escapes back into its native representation.

This tool doesn't really have much use if you're already using ASCII to formulate your Java programs, but is of value if you're using some other character set.


Informations Method in Class

In issue #013 we talked about reflection, a new feature whereby a running program can examine and manipulate class and primitive types within the program. Reflection relies on hooks in java.lang.Class.

Beyond added support for reflection, Class also has some new methods for querying properties of types. To see how these work, consider an example such as:
        class A {}
        class B extends A {}

        public class test {
                public static void main(String args[])
                {
                        Object obj1 = new int[10];
                        Class c1 = obj1.getClass();
                        System.out.println(c1.isArray());
                        System.out.println(c1.getComponentType());

                        Class c2 = Double.TYPE;
                        System.out.println(c2.isPrimitive());

                        Object obj3 = new A();
                        Object obj4 = new B();
                        System.out.println(obj3.getClass().isInstance(obj4));

                        Class c3 = A.class;
                        Class c4 = B.class;
                        System.out.println(c3.isAssignableFrom(c4));
                        System.out.println(c4.isAssignableFrom(c3));
                }
        }

In the first block of code, we create an array and assign it to an Object reference. We then create a Class object to represent the array, and query the object. isArray() returns true if the Class object is an array, and getComponentType() returns the underlying primitive type ("int" in this case).

isPrimitive() is used to determine whether a Class object type represents a primitive type such as "double".

isInstance() is the programmatic equivalent of the "instanceof" operator. In the example above, we are essentially saying:
        B object instanceof A

which is true, because a subclass object is an instance of its superclass type.

Finally, isAssignableFrom() is used to check whether one class reference can be assigned to another. In this example, a B reference can be assigned to an A one, but not the other way around.

The program output is:
        true
        int
        true
        true
        true
        false

Even if you don't use reflection, these methods are sometimes useful in figuring out what sort of a type is being manipulated. Given a non-null Object reference, you can get its Class object by calling getClass(), and then use these methods.


Properties

In issue #016 we talked about the use of Hashtable to store lists. java.util.Properties is a subclass of Hashtable optimized for storing and manipulating name=value pairs.

A simple example of using the Properties class is this:

        import java.util.Properties;

        public class prop {
                public static void main(String args[])
                {
                        Properties pr = System.getProperties();
                        pr.list(System.out);
                }
        }

which displays system properties. For example, on my system the output is:
        -- listing properties --
        user.language=en
        java.home=e:\java\bin\..
        awt.toolkit=sun.awt.windows.WToolkit
        file.encoding.pkg=sun.io
        java.version=1.1.3
        file.separator=\
        line.separator=

        user.region=US
        file.encoding=8859_1
        java.compiler=symcjit
        java.vendor=Sun Microsystems Inc.
        user.timezone=GMT
        user.name=glenm
        os.arch=x86
        os.name=Windows NT
        java.vendor.url=http://www.sun.com/
        user.dir=G:\tmp
        java.class.path=.;e:/java/lib/classes.zip;e:\java\bin...
        java.class.version=45.3
        os.version=4.0
        path.separator=;
        user.home=g:/.

Besides the features of Hashtable (such as the get() and put() methods), Properties supports the loading/saving of property lists to streams (typically disk files), and supports default properties that are used if a given property cannot be found.

Beyond the use for representing system characteristics, properties are heavily used in internationalization, to provide locale-specific settings. For example, a menu label can be given a tag such as "exitTag", and this name looked up in a property file to find the corresponding value that represents the label text for a given language. PropertyResourceBundle is an example of a class that uses Properties and that is targeted at internationalization support.


Hashcode

hashCode() is a method defined in java.lang.Object, the superclass of all Java class types. It returns a hash code such as is needed by java.Util.Hashtable.

For a given object, hashCode() always returns the same value, when invoked multiple times during one Java program execution. However, the value returned may be different from one execution to another, and therefore permanently storing a hash code value, for example via serialization, does not make sense. It's interesting to note that when a Hashtable is serialized, only the key/value pairs are saved, and not the internally saved hash code values, which may change at the point of deserialization.

Also, hashCode() has the property that if calling Object.equals() to compare two objects returns true, then the hashCode() methods for the two objects must return identical results. Of course, hashCode() can also return identical values for unequal objects.

The Object version of hashCode() will typically calculate the hash code by converting the internal object address into an integer, but there is no guarantee that the code will be computed in this way. Subclasses such as java.lang.String reimplement hashCode() to calculate a value that takes into account the specific characteristics of the particular type of data being manipulated.


IdentityHashcode

Another aspect of hashCode() is a new feature in 1.1, the method System.identityHashCode(). This method can be used to compute the hash code that Object.hashCode() would have come up with, even if the given object's class overrides hashCode().

So, for example, running this program:
        public class test {

                public static void main(String args[])
                {
                        String s = "this is a test";

                        System.out.println(s.hashCode());

                        System.out.println(System.identityHashCode(s));

                        System.out.println(System.identityHashCode(null));
                }

        }

results in three different values being printed. The first one is computed via String.hashCode(). The second one computes the value that Object.hashCode() would come up with, and the third value printed is 0 for the null reference.

This feature is used for doing object serialization, among other places. It is useful when dealing with a variety of object types. Each type may have its own hashCode() suitable for representing that type, but not optimal across other types.


Sort

Java 1.1 offers no standard way to sort lists of elements. This deficiency has been remedied in 1.2 using a combination of mechanisms. The first of these is the java.lang.Comparable interface, that imposes an ordering on object instances of classes that implement the interface. Such classes include all the standard wrapper classes such as Float and Long, together with the String class. It's therefore possible to say, for example, whether one String is ordered before another for purposes of sorting.

There is an analogous interface java.util.Comparator for specifying user-defined orderings. Comparator.compare(Object, Object) returns a value indicating whether the first object is ordered before the second, is equal to it, or comes after it.

The third new feature is the whole Collections framework. In 1.2 java.util has a number of important new classes and interfaces, that implement collections of elements. These include lists, maps, sets, and trees. The existing Vector class has also been brought into this framework. Collections are a topic of their own that we may discuss at some point.

One of the algorithms implemented for collections is sort(), and thus we can say:
        import java.util.*;

        public class compare {
                public static void main(String args[])
                {
                        Vector vec = new Vector();

                        vec.addElement("apple");
                        vec.addElement("peach");
                        vec.addElement("orange");
                        vec.addElement("banana");
                        vec.addElement("tangerine");

                        Collections.sort(vec);

                        for (int i = 0; i < vec.size(); i++)
                                System.out.println((String)vec.elementAt(i));
                }
        }

This uses the standard java.lang.Comparable ordering defined on Strings. We could impose our own ordering for sort() by specifying a class object that implements java.util.Comparator.


File

We've been looking at some of the classes contained in the Java core libraries. Another interesting one of these is java.io.File. This class is used to represent files, with a variety of operations supported. To illustrate some of the operations, consider a program for walking through a directory structure:
        import java.io.*;
        import java.util.*;

        public class FileWalker {

                private Stack stk = new Stack();

                public FileWalker(String fn)
                {
                        stk.push(fn);
                }

                public synchronized String getNext()
                {
                        if (stk.empty())
                                return null;

                        String fn = (String)stk.pop();
                        File f = new File(fn);

                        if (f.isDirectory()) {
                                String lst[] = f.list();
                                int len = lst.length - 1;
                                for (int i = len; i >= 0; i--) {
                                        File f2 = new File(fn, lst[i]);
                                        stk.push(f2.getPath());
                                }
                        }

                        return f.getPath();
                }

                public static void main(String args[])
                {
                        FileWalker fw = new FileWalker(args[0]);

                        String path = null;
                        while ((path = fw.getNext()) != null)

                                System.out.println(path);
                }

        }

The idea here is to keep a stack of directories/files to be visited, and then visit them in turn. When subdirectories are encountered, their entries are stacked up as well.

File represents a file or directory, and operations such as asking whether a given path is a directory or not are supported. The contents of a directory can be looked up using the list() method, and this feature is used to traverse subdirectories and get their entries. The entries are pushed on the stack and traversed in turn.

Note that we use a File constructor that takes a directory and an entry in that directory, to form a new item to be pushed on the stack for later traversal. And then later we use getPath() to return the actual paths. What we avoid doing is making assumptions about path separators like "\" or "/". This issue is handled internally within the File class.

getNext() is a synchronized method, meaning that the Java Virtual Machine obtains a lock on the underlying object before the method is entered. Why does this matter? If two threads are using a FileWalker object, and both of them call getNext() simultaneously without any synchronization being done, confusion may result due to the fact that getNext() updates its internal state (the stack). Synchronization guarantees that only one thread will execute getNext() at a time.


I/O Speedups

Suppose that you'd like to count the number of text lines in a file.
One way of doing this is to say:

        import java.io.*;

        public class test4 {

                public static void main(String args[])
                {
                        try {
                                FileInputStream fis =
                                    new FileInputStream(args[0]);
                                DataInputStream dis =
                                    new DataInputStream(fis);
                                int cnt = 0;
                                while (dis.readLine() != null)
                                        cnt++;
                                fis.close();
                                System.out.println(cnt);
                        }
                        catch (Throwable e) {
                                System.err.println("exception");
                        }
                }

        }

This is quite slow, in part because DataInputStream.readLine() does a method call (read()) for each character.

A faster way in Java 1.1 is to say:

        import java.io.*;

        public class test3 {

                public static void main(String args[])
                {
                        try {
                                FileReader fr = new FileReader(args[0]);
                                BufferedReader br = new BufferedReader(fr);
                                int cnt = 0;
                                while (br.readLine() != null)
                                        cnt++;
                                fr.close();
                                System.out.println(cnt);
                        }
                        catch (Throwable e) {
                                System.err.println("exception");
                        }
                }
        }

This runs about 4 times as fast as the old approach, and avoids a read() call for each character. readLine() in this case grabs the underlying data in large buffered chunks.


Class Literals

In Java the class "java.lang.Class" has always been used to represent class and interface types. A statement like:
        Class c = null;

        try {
                c = Class.forName("java.lang.String");
        }
        catch (Throwable e) {
        }

will dynamically load the specified class if it is not already loaded. In Java 1.0 a Class object can also represent arrays, as a special type of class.

In Java 1.1, this notion has been broadened to include any Java type, and there is an easier way to obtain the Class object for a type. For example, the following code prints "equal":
        public class test1 {

                public static void main(String args[])
                {
                        try {
                                Class c1 = Class.forName("java.lang.String");
                                Class c2 = java.lang.String.class;
                                if (c1 == c2)
                                        System.out.println("equal");
                        }
                        catch (Throwable e) {
                        }
                }

        }

In this example the new approach uses ".class" appended to a class specification to get the Class object reference.

This feature can also be used on fundamental types, for example:
        public class test2 {

                public static void main(String args[])
                {
                        Class c1 = Integer.TYPE;
                        Class c2 = int.class;

                        if (c1 == c2)
                                System.out.println("equal");
                }

        }

That is, a type like "int" can be represented via a Class object.

One reason why this new feature is important is that Java 1.1 also introduces nested or inner classes, classes defined within other classes. Java uses a name like "A$B.class" to name a disk file that refers to a class B nested in a class A, and using the older Class.forName() approach requires knowledge of this encoding.


BitSet

A simple but valuable class in java.util is BitSet, used for keeping track of a set of boolean values. For example, this code:
        import java.util.*;

        public class test5 {

                public static void main(String args[])
                {
                        BitSet b = new BitSet();

                        b.set(57);
                        b.set(109);
                        b.set(0);
                        b.clear(109);

                        for (int i = 0; i < 200; i++) {
                                if (b.get(i))
                                        System.out.print(i + " ");
                        }

                        System.out.println();
                }

        }

displays the output:
        0 57

The set of values grows dynamically as needed. It is also possible to compare two sets, or perform AND, OR, and XOR operations.


Stack

In Java the Vector class (java.util.Vector) is widely used in a variety of ways, to store lists of objects.

A lesser-known class, that is a subclass of Vector, is Stack. Stack supports a last-in-first-out (LIFO) set of objects, and uses the usual operations -- push(), pop(), and so on. For example, this program will display a list of numbers in descending order:
        import java.util.*;

        public class stack {

                public static void main(String args[])
                {
                        Stack st = new Stack();

                        for (int i = 1; i <= 10; i++)
                                st.push(new Integer(i));

                        while (!st.empty())
                                System.out.println(st.pop());
                }

        }

There is also a peek() method for examining the top of stack value without popping it.

Stack is derived from Vector, and as such, the methods of Vector are also available to a Stack user. But it is perhaps not a good idea to take advantage of this fact, for example by inserting a value into the middle of the stack. Doing so breaks the stack paradigm and makes it harder to reason about the operation of a program.


Accessing Instance Variables

Consider a bit of code like:
        public class perf1 {

                private char buf[] = new char[4096];

                public int find(char c)
                {
                        for (int i = 0; i < buf.length; i++) {
                                if (buf[i] == c)
                                        return i;
                        }

                        return -1;
                }

                public static void main(String args[])
                {
                        perf1 p = new perf1();

                        int n = 2500;
                        while (n-- > 0)
                                p.find('x');
                }

        }

where there is an object instance of a class, with an internal buffer that you want to search repeatedly. This code runs pretty slowly (around 14.5 seconds on a slow Pentium with JDK 1.1.2). Is there any way to speed it up?

There are a couple of improvements that can be made, centering around accessing instance variables (fields) of an object. It turns out that such access is quite slow, with calls to the "getfield" instruction in the Java Virtual Machine. That is, the above code accesses "this.buf" twice in each iteration of the loop in find(), once for determining buf.length and the other for accessing buf[i].

Rewriting the code as:
        public class perf2 {

                private char buf[] = new char[4096];

                public int find(char c)
                {
                        char xbuf[] = buf;

                        for (int i = 0; i < xbuf.length; i++) {
                                if (xbuf[i] == c)
                                        return i;
                        }

                        return -1;
                }

                public static void main(String args[])
                {
                        perf2 p = new perf2();

                        int n = 2500;
                        while (n-- > 0)
                                p.find('x');
                }

        }

results in around a 15% speedup, with the reference to "this.buf" replaced by a local stack-based variable "xbuf". This simply adds another reference to buf, with no copying of data or anything implied. A Java compiler might be able to automatically supply this optimization.

A further speedup can be realized by saying:

        public class perf3 {

                private char buf[] = new char[4096];

                public int find(char c)
                {
                        char xbuf[] = buf;

                        int n = xbuf.length;

                        for (int i = 0; i < n; i++) {
                                if (xbuf[i] == c)
                                        return i;
                        }

                        return -1;
                }

                public static void main(String args[])
                {
                        perf3 p = new perf3();

                        int n = 2500;
                        while (n-- > 0)
                                p.find('x');
                }

        }

to eliminate calls to the JVM "arraylength" instruction. This gives another 10%, or a total of 25% from the original code.

Of course, such tweaking has a downside, leading to more obscure code. But it's a useful performance improvement in certain cases where instance variables in a class are heavily accessed.


Wrapper Classes

In Java, it is possible to represent a set of primitive types like integers in at least two ways. One is simply as an array of actual values:
        int x[] = {1, 2, 3};

while the other uses a wrapper class:
        Integer x[] = {new Integer(1), new Integer(2), new Integer(3)};

In terms of actually representing a set of values, the first of these is more efficient in speed and space, while the second is more general. As a rule of thumb, representing an integer via a wrapper takes about 12-16 bytes, compared to 4 in an actual array of ints. And retrieving the value of the integer using Integer.intValue() may involve a method call.

But if you need to store a list of integers in a Vector or Hashtable, or you'd like to store an integer in a mixed list of values (for example, Integers and Strings), then the wrapper is the only way to go. Wrapper classes exist for all primitive types, with some of the wrapper classes such as Short added in 1.1.

These classes have another important function, which is to group together a set of methods that operate on actual primitive types. For example, consider the class (static) method Integer.toHexString(int). This can be used to display an integer in hex format:
        public class test {
                public static void main(String args[])
                {
                        int i = 123456;
                        System.out.println(Integer.toHexString(i));
                }
        }

Beyond the usual methods for converting primitive types to Strings and back again, and the accessor methods like intValue(), the wrapper classes also define constants for a given primitive type. For example, Short.MAX_VALUE is 32767, the largest value that may be represented by a short. Float and Double also have constants for negative and positive infinities and for NaN (a special constant, not-a-number).

The Character class has a variety of methods for categorizing characters, for example the isLetter(char) method. These methods work by consulting a large table found within Character.java in the JDK source code. If you are used to using C/C++, these methods may be familiar, but their implementation is far more complex because the Unicode character set is used. What constitutes a letter in Unicode is quite different than asking a similar question when using the ASCII character set.


Sizeof for Java

In previous issues we've mentioned that Java has no sizeof() operator like C/C++. With uniform sizes for primitive data types, and a different style of memory allocation, the need for sizeof() really isn't there. And it's hard to define what sizeof() would mean anyway, given that an object may not contain other objects, but only references to them.

But it's interesting to experiment with the 1.1 reflection feature and see whether a method can be devised that will return useful information about object sizes.

The Sizeof class below tries to do this, for a passed-in data structure. It walks the structure and tallies up the total size in bytes. It ignores alignment and packing issues and hidden fields in structures, and assumes a boolean is of size 1 and a reference of size 4 (reference sizes may vary; for example SZ_REF might be 8 on a machine with 64-bit pointers).

It does not count static data members of class instances, but does include members inherited/implemented from superclasses and interfaces. It does not follow references in object instances or in arrays, except for the case of a multi-dimensional array, where the reference is to another array.

Included are some tests that illustrate what results are expected in given cases.
        import java.lang.reflect.*;

        class test_Class1 {
                private int a1;
                public byte a2;
                protected char a3[];
                static byte a33;
        }

        class test_Class2 extends test_Class1 {
                static float a33;
                byte a3;
                short a4;
                double a5[] = new double[10];
        }

        class test_Class3 extends test_Class2 {
                boolean a4;
                static int a44;
                char a5;
                long a6;
        }

        interface test_Class4 {
                public byte x = 1;
        }

        interface test_Class5 extends test_Class4 {
                public int x = 2;
        }

        class test_Class6 {
                public double x;
        }

        class test_Class7 extends test_Class6 implements test_Class5 {
                char x[] = null;
        }

        public class Sizeof {

                private static final int SZ_REF = 4;

                public static int sizeof(boolean b)      {  return 1;  }
                public static int sizeof(byte b)         {  return 1;  }
                public static int sizeof(char c)         {  return 2;  }
                public static int sizeof(short s)        {  return 2;  }
                public static int sizeof(int i)          {  return 4;  }
                public static int sizeof(long l)         {  return 8;  }
                public static int sizeof(float f)        {  return 4;  }
                public static int sizeof(double d)       {  return 8;  }

                private static int size_inst(Class c)
                {
                        Field flds[] = c.getDeclaredFields();
                        int sz = 0;

                        for (int i = 0; i < flds.length; i++) {
                                Field f = flds[i];
                                if (!c.isInterface() &&
                                    (f.getModifiers() & Modifier.STATIC) != 0)
                                        continue;
                                sz += size_prim(f.getType());
                        }

                        if (c.getSuperclass() != null)
                                sz += size_inst(c.getSuperclass());

                        Class cv[] = c.getInterfaces();
                        for (int i = 0; i < cv.length; i++)
                                sz += size_inst(cv[i]);

                        return sz;
                }

                private static int size_prim(Class t)
                {
                        if (t == Boolean.TYPE)          return 1;
                        else if (t == Byte.TYPE)        return 1;
                        else if (t == Character.TYPE)   return 2;
                        else if (t == Short.TYPE)       return 2;
                        else if (t == Integer.TYPE)     return 4;
                        else if (t == Long.TYPE)        return 8;
                        else if (t == Float.TYPE)       return 4;
                        else if (t == Double.TYPE)      return 8;
                        else if (t == Void.TYPE)        return 0;
                        else                            return SZ_REF;
                }

                private static int size_arr(Object obj, Class c)
                {
                        Class ct = c.getComponentType();
                        int len = Array.getLength(obj);

                        if (ct.isPrimitive()) {
                                return len * size_prim(ct);
                        }
                        else {
                                int sz = 0;
                                for (int i = 0; i < len; i++) {
                                        sz += SZ_REF;
                                        Object obj2 = Array.get(obj, i);
                                        if (obj2 == null)
                                                continue;
                                        Class c2 = obj2.getClass();
                                        if (!c2.isArray())
                                                continue;
                                        sz += size_arr(obj2, c2);
                                }
                                return sz;
                        }
                }

                public static int sizeof(Object obj)
                {
                        if (obj == null)
                                return 0;

                        Class c = obj.getClass();

                        if (c.isArray())
                                return size_arr(obj, c);
                        else
                                return size_inst(c);
                }

                private static void err(String s)
                {
                        System.err.println("*** " + s + " ***");
                }

                private static void test()
                {
                        if (sizeof(null) != 0)
                                err("null");

                        if (sizeof(true) != 1)         err("boolean");
                        if (sizeof((byte)37) != 1)     err("byte");
                        if (sizeof('x') != 2)          err("char");
                        if (sizeof((short)37) != 2)    err("short");
                        if (sizeof(37) != 4)           err("int");
                        if (sizeof(37L) != 8)          err("long");
                        if (sizeof(37.0f) != 4)        err("float");
                        if (sizeof(37.0) != 8)         err("double");

                        if (sizeof(new boolean[0]) != 0)
                                err("boolean[0]");
                        if (sizeof(new byte[10]) != 10)
                                err("byte[10]");
                        if (sizeof(new char[10][10]) != 200 + 10 * SZ_REF)
                                err("char[10][10]");
                        if (sizeof(new short[10][11][12]) != 2640 +
                            120 * SZ_REF)
                                err("short[10][11][12]");
                        if (sizeof(new int[0][10]) != 0)
                                err("int[0][10]");

                        if (sizeof(new String[100]) != 100 * SZ_REF)
                                err("String[100]");
                        if (sizeof(new String[10][10]) != 110 * SZ_REF)
                                err("String[10][10]");

                        Object ov[] = new Object[3];
                        ov[0] = new byte[10];
                        ov[2] = new double[10];
                        if (sizeof(ov) != 90 + 3 * SZ_REF)
                                err("Object[3]");

                        String sv[] = new String[10];
                        for (int i = 0; i < 10; i++)
                                sv[i] = new String();
                        if (sizeof(sv) != 10 * SZ_REF)
                                err("String[10]");

                        if (sizeof(new Object()) != 0)
                                err("Object");
                        if (sizeof(new Integer(37)) != 4)
                                err("Integer(37)");

                        if (sizeof(new test_Class1()) != 5 + SZ_REF)
                                err("test_Class1");
                        if (sizeof(new test_Class2()) != 8 + 2 * SZ_REF)
                                err("test_Class2");
                        if (sizeof(new test_Class3()) != 19 + 2 * SZ_REF)
                                err("test_Class3");

                        if (sizeof(new test_Class7()) != 13 + SZ_REF)
                                err("test_Class7");
                }

                public static void main(String args[])
                {
                        test();
                }
        }


Printing

People often ask about how to do printing in Java. There are at least two ways this can be done. We will illustrate one approach here, and another later in this issue.

One simple way to print is to use device files. With UNIX, this involves writing into the file /dev/lp, and with Windows, use of a file called "lpt1". Bytes written into such a file show up on the printer. For example:
        import java.io.*;

        public class lpr {

                public static void main(String args[])
                {
                        try {
                                FileOutputStream fos =
                                    new FileOutputStream("lpt1");
                                String s = args[0];
                                for (int i = 0; i < s.length(); i++)
                                        fos.write((byte)s.charAt(i));
                                fos.write((byte)0xC);
                                fos.close();
                        }
                        catch (Throwable e) {
                                System.err.println("*** exception ***");
                        }
                }
        }

This will print the specified string on the printer, and then issue a form feed (0xC).

Normally, "lpr" would be expanded to do several additional things, for example expanding tabs, putting margins at the top and bottom and sides of the page, and handling multiple copies.

This particular example sidesteps the issues of coordinating printing with a print queue manager, displaying Unicode, remote printing, and so on.

Below is another printing example, this one using the Abstract Windowing Toolkit.


StringBuffer

In Java String objects are immutable, that is, they cannot be changed once created. For example:
        String s = "abc";
        String t = s;

        s = s.toUpperCase();

        System.out.println(t);

displays "abc", not "ABC". Both s and t start out referring to a String object. That object does not change when the upper case conversion is done, but instead, another object is created and s is made to refer to it.

For operations involving mutable strings, the class StringBuffer can be used. Some of its methods, like charAt(), overlap those found in String, but many of the operations focus on building up new strings of characters. There are many append() methods, for example.

For example, the "+" operator on strings in Java is implemented by replacing a line such as:
        String s = "xyz" + 37;

with:
        s = (new StringBuffer("xyz")).append(37).toString();

For accumulating strings, a quick and dirty approach like:
        String s = "";

        s += "xyz";

can be used, but this is a lot more expensive than using StringBuffers, because the String must be converted to a StringBuffer and back again. In issue #004 we gave an example where using a StringBuffer resulted in about a 6X speedup. In this example, we would say:
        StringBuffer sb = new StringBuffer();

        sb.append("xyz");

        String s = sb.toString();

In the next section we will look further at StringBuffer performance.


Appending Chars

One of the most common uses of StringBuffer is to accumulate a set of characters, and then convert the result to a String:
        StringBuffer sb = new StringBuffer();

        sb.append('a');
        sb.append('b');
        sb.append('c');

        String s = sb.toString();

Is it possible to improve on the performance of the StringBuffer append() method? At the moment, the answer appears to be yes:
        public class AppendChar {
                private char buf[] = null;
                private int len = 0;

                public AppendChar()
                {
                        buf = new char[16];
                }

                public synchronized void append(char c)
                {
                        if (len == buf.length) {
                                char x[] = new char[len * 2];
                                System.arraycopy(buf, 0, x, 0, len);
                                buf = x;
                        }
                        buf[len++] = c;
                }

                public String toString()
                {
                        return new String(buf, 0, len);
                }
        }

This runs about twice as fast as the standard version, because it internally handles checking of overflow, instead of calling ensureCapacity().

Whether it is "right" to roll your own version of a library method depends on how desperate for speed you are. Most of the time, append() speed doesn't matter, but when it does, this approach may be useful. One of the classic performance bottlenecks is that of doing lots of operations for every character of input in a program.

If you're particularly interested in Java performance, see the Web page http://www.glenmccl.com/~glenm/perflib/index.html

for further information about this type of approach. This page describes a Java performance library.


String Tokenizer / HashTable

Java is similar to other programming languages in that it consists of the actual Java language, with libraries added on. We're going to use the generic term "library" to refer to what is often called an "API" or a "package".

The term "core" is also used to refer to certain of the libraries that are required to run a Java program. Core libraries include:
        java.lang

        java.util

        java.io

The language proper "knows" about some of these. For example, the operator "+" has a certain meaning when applied to Strings. And standard I/O that is made available to a running Java program relies of course on the java.io package.

We will be exploring the use of some of the library classes in a series of columns. In the first one, we'll look at two classes found in java.util, Hashtable and StringTokenizer, and a helper interface known as Enumeration.

Suppose that you'd like to write a program that reads from a file and displays a list of all the unique words in the file. How might this be done? We'll assume that a "word" is any sequence of characters delimited by whitespace.

One approach looks like this:
        import java.util.*;
        import java.io.*;

        public class Word {

                public static void doit(String fn)
                {
                        Hashtable ht = new Hashtable();

                        try {
                                FileInputStream fis = new FileInputStream(fn);
                                DataInput d = new DataInputStream(fis);
                                String s = null;
                                while ((s = d.readLine()) != null) {
                                        StringTokenizer st =
                                           new StringTokenizer(s);
                                        while (st.hasMoreTokens())
                                                ht.put(st.nextToken(), "");
                                }
                                fis.close();
                        }
                        catch (Throwable e) {
                                System.err.println("*** exception ***");
                        }

                        Enumeration en = ht.keys();
                        while (en.hasMoreElements())
                                System.out.println((String)en.nextElement());
                }

                public static void main(String args[])
                {
                        doit(args[0]);
                }

        }

We first set up to read lines from a disk file. As each line is read, we create a StringTokenizer class instance. This class is used to split a String into pieces. By default, the delimiters are space, tab, carriage return, and newline (" \t\r\n"), but you can specify your own set of delimiters to the StringTokenizer constructor.

We iterate based on hasMoreTokens(), picking off each token in turn. These tokens, as Strings, are added to the hash table. put() takes two Object parameters, a key and a value. A String is derived from Object, and may be supplied as a key argument. We don't care about the associated value with the String key, and so we use "" for this. If we did care, for example to count how many times each word occurs, we could set up a Counter class type and supply an instance of it as the value.

A hash table contains only one instance of each key. To find out what words were encountered, we can retrieve the keys and display them. This is done via an Enumeration. Enumeration is not a class, but an interface. That is, it specifies a set of methods that a class that "implements" it must define. The two methods in this case are hasMoreElements() and nextElement(). The keys() method in Hashtable returns an HashTableEnumerator class instance. Because it implements Enumeration, it can be manipulated in a way similar to the superclass / subclass paradigm, through a reference to an Enumeration.

The key hook required to make a Hashtable work is the hashCode() method defined in Object and overridden by derived classes such as String. hashCode() supplies the raw value used to insert an entry into the table.

The approach outlined here is quite simple to use. If you are desperate for performance, some lower-level techniques are faster, though not as convenient.


Javaw

Suppose that you'd like to take the program from the previous section and run it in the Windows environment, using an icon to invoke it (rather than from the command line). How would you do this? There is a program called "javaw" that comes with the JDK. You can use it to run standalone AWT programs using a Windows interface.

To do this, you need to set up a new Program Item in the standard way, with entries like:
        Description:  Delegate

        Command Line:  e:\java\bin\javaw Delegate (this will vary)

        Working Directory:  g:\tmp (this will vary)

When you click on the icon, the program will come up.

There's a certain amount of magic in making something like this work, but if you're interested in this area, you might try experimenting with this technique.


Conditional Compilation

In issue #011 we talked about Java's lack of a preprocessor, such as used in C and C++. This lack is both a blessing and a curse. One common idiom in C is to use conditional compilation, for example, the use of DEBUG to control program execution and possibly take different action such as dumping out more information to the user:
        #ifdef DEBUG

        debugging stuff ...

        #endif

The preprocessor runs before the compiler proper and so the use of #ifdef results in different subsets of the program actually being compiled based on which constants (such as DEBUG) are set.

In Java, we could achieve a similar end by saying something like:
        public class test1 {

                public static final boolean DEBUG = false;

                public static void main(String args[])
                {
                        for (int i = 1; i <= 10; i++) {
                                if (DEBUG)
                                        System.out.println("i = " + i);
                        }
                }
        }

which will dump out the loop index at each loop iteration, if DEBUG is true.

There is a quirk with this worth noting. A program like:
        public class test2 {

                void f()
                {
                        int x = 0;

                        while (false)
                                x = -37;
                }
        }

is invalid, even thought it's superficially like the one above, in that in one case we have:
        if (false)
                statement;

and in the other:
        while (false)
                statement;

In both cases the statement is unreachable, but Java special cases the "if" case, in order to support conditional compilation. See 14.19 in the "Java Language Specification" for a more detailed discussion of this point.

This approach to "conditional compilation" still requires that the code be valid. That is, with use of the C/C++ preprocessor conditional compilation is textually based, in that excluded code is never presented to the actual compiler, whereas the scheme above is logically based -- the code is simply never executed.


JACK

Lex and Yacc are widely-used tools for doing lexical scanning and parsing of input. You describe the structure of the input and these tools generate programs (in C) that will accept and structure such input. For example, an identifier might be lexically described as:
        [a-zA-Z_][a-zA-Z_0-9]*

meaning that the identifier starts with a letter or underscore, followed by zero or more letters, underscores, or digits.

Similarly, a simple expression in BNF (Backus Naur Form) could look like:
        E -> T | E + T

        T -> F | T * F

        F -> number | ( E )

This is known as a grammar, and programming languages like Java are formally described via a grammar. O'Reilly and others publish books on Lex/Yacc, if you want information on these tools.

Jack is a new tool that combines Lex and Yacc capabilities. It's written in Java and produces Java output, that is, produces Java programs for parsing input described via a grammar. Jack is available on the Web at http://www.suntest.com/Jack

You need the Java Development Kit 1.0.2 to use this program. With Jack you describe the lexical and syntactic structure of your program, and then have it produce Java programs that understand this structure.

As an example of a problem made simple by a tool of this type, consider the issue of extracting from Java programs basic information about what is defined where, for example, where a specific class or method is found in the source code. With Jack, it's simply a matter of dumping out key information whenever a particular construct like a method declaration is found.

For example, we might have this format for the output:
        String.charAt method 204 java/src/java/lang/String.java

meaning that the charAt() method of class String is defined at line 204 of String.java.

An index produced in this format, representing all the classes, interfaces, methods, and constructors for JDK 1.0.2, is available via FTP at ftp://ftp.glenmccl.com/morespace1/glenmccl/jack

along with a simple UNIX shell script browser to search and access any of the symbols in the database.

There are many other possibilities for the use of a tool of this type, for example test coverage or generation of class metrics. If you have interest in this area, please send me a note (glenm@glenmccl.com).


JavaScript

You may have heard the term "JavaScript". What is its relation to Java and HTML? JavaScript started out as LiveScript and its connection to Java is fairly loose, sharing some Internet heritage but not that much else.

HTML (Hyper Text Markup Language) is not really a programming language in the usual sense of the term, but rather a language that describes what a page ought to look like. You can't really "do anything" with HTML.

Java is a general purpose programming language. One type of Java program, an applet, is downloadable by a Web browser and then executed locally by the browser. This is useful, for example, in communicating with remote databases. An applet's invocation is described via the HTML tags <applet> and </applet>.

JavaScript can be viewed as a language something like Perl, or as an extension of HTML to allow customized functionality. As an example of what a JavaScript application would look like, consider this example:
        <html>
        <body>

        <a href="link1.html">Link #1</a>
        <br>
        <a href="link2.html">Link #2</a>
        <br>

        <script>

        <!--

        function doit()
        {
                document.write("<br>This page's links are:<br><br>");
                for (var i = 0; i < document.links.length; i++) {
                        var s = "";
                        s += (i + 1) + ".  ";
                        s += document.links[i];
                        s += "<br>";
                        document.write(s);
                }
        }

        doit()

        <!-- -->

        </script>

        </body>
        <html>

This particular application iterates over the links in a page and displays them in a numbered list:
        1.  link1.html

        2.  link2.html

JavaScript as a programming language has a flavor something like Perl or Awk, with weak typing and domain-specific system variables like "document.links[]".

Note that the output of a JavaScript script is HTML, so for example we use "<br>" instead of "\n" to go to the next line. In the above example, the function doit() is defined, and then called to produce HTML.

We will probably not say more about JavaScript, but there are a variety of books available on the topic. You need a Web browser like Netscape 3.0 to execute JavaScript programs.


Binary Search Class

As we've discussed previously, there are still some issues around the performance of Java, and thus there is a premium on the use of efficient algorithms.

One such algorithm is the familiar one of binary search, where a sorted list is searched by continually halving the search area until the desired element is found or it is determined that the element is not in the list.

In Java this might look like:
        import java.util.Vector;

        public class Search {

                // no one should instantiate this class
                // since it exists only as a packaging vehicle
                // for the static method search()

                private Search() {}

                public synchronized static int search(Vector v, Object objp,
                    Orderable op)
                {
                        if (v == null || objp == null || op == null)
                                throw new IllegalArgumentException("null arg");

                        int low = 0;
                        int high = v.size() - 1;
                        while (low <= high) {
                                int mid = (low + high) / 2;
                                int c = op.compareTo(objp, v.elementAt(mid));
                                if (c < 0)
                                        high = mid - 1;
                                else if (c > 0)
                                        low = mid + 1;
                                else
                                        return mid;
                        }
                        return -1;
                }
        }

where an index 0 <= index < N is returned, or -1 if the element is not found. The Vector class found in Java does not automatically maintain a sorted order for the items in the vector.

This algorithm is straightforward save for the notion of an
Orderable. What is this? An Orderable is an interface:

        public interface Orderable {
                public int compareTo(Object p1, Object p2);
        }

If a given class implements an interface, that means that it defines the methods of the interface. This is the method of choice at the moment for passing a method reference as an argument, or in C/C++ terms, passing a pointer to a function. In other words, we create an instance of a class that implements the Orderable interface, which means that the instance will have a compareTo() method that we can call out to.

To see how this works, consider this example that uses the search class:
        import java.util.*;

        class Ord implements Orderable {
                public int compareTo(Object p1, Object p2)
                {
                        int n1 = ((Integer)p1).intValue();
                        int n2 = ((Integer)p2).intValue();

                        if (n1 > n2)
                                return 1;
                        else if (n1 < n2)
                                return -1;
                        else
                                return 0;
                }
        }

        public class test {
                public static void main(String args[])
                {
                        Vector v = new Vector();
                        int N = 10000;
                        int i = 0;

                        for (i = 0; i < N; i++)
                                v.addElement(new Integer(i));

                        for (i = 0; i < N; i++)
                                Search.search(v, new Integer(i), new Ord());
                }
        }

We create a Vector of 10000 integers, each wrapped in an Integer wrapper. We then search for each in turn, passing to Search.search() an object instance of Ord, a class that implements the Orderable interface and thus is guaranteed to contain a compareTo() method for comparing two Object references that refer to Integer wrappers.

This approach is somewhat like the bsearch() library function in ANSI C. A similar technique can be used for sorting. The above search class is part of a Java class library described on the Web page:
        http://www.glenmccl.com/~glenm/javalib/index.html



Garbage Collection and Setting to Null

In issue #001 we talked about Java garbage collection, where the runtime system automatically reclaims dynamic storage that is no longer in use. For example:
        public class test {
                public void f()
                {
                        char buf[] = new char[1024];
                        // stuff that uses buf
                }
        }

When method f() exits, the space that buf uses is garbage, because only a local variable in an invalid stack frame references it. The runtime system may eventually reclaim the storage.

Garbage collection is automatic. But sometimes there are ways to help it out. Consider a case where you are managing a stack of Object references:
        public class Stack {

                private static final int MAXLEN = 10;

                private Object stk[] = new Object[MAXLEN];

                private int stkp = -1;

                // add in logic for error checking, stack growing, etc. ...

                public void push(Object p)
                {
                        stk[++stkp] = p;
                }

                public Object pop()
                {
                        return stk[stkp--];
                }
        }

Consider a case where the stack has two elements on it, and you pop one of them. At this point stk[0] will have a valid element in it, and stk[1] will have the element just popped. That is, stk[1] will have a reference to an Object, which could be a reference to anything, including a large data structure of many thousands of bytes. In such a case, this data structure cannot be garbage collected, even though it may no longer be in use.

To remedy this problem, we can rewrite pop() like so:
        public Object pop()
        {
                Object p = stk[stkp];
                stk[stkp--] = null;
                return p;
        }

We haven't nullified the Object itself, just a no longer valid reference to it. The Stack object itself may have a long lifetime, and rewriting the pop() method in this way helps ensure that garbage collection can be done in a timely way.


Fast I/O for Text Lines

In issue #002 we traced through the steps involved in doing Java character output. The Java I/O system offers flexibility in structuring various sorts of I/O, with the possibility of adding filtering layers and so on.

But this flexibility has a performance cost, caused in part by the layers themselves and in part by the method call overhead. As we've said previously, Java is a young language and it's not totally clear how various pieces will shake out. But it's worth considering how some common types of I/O might be speeded up.

As an example, consider text lines. These are lines of characters ending in \n while being manipulated in a program, and ending in \r\n or \n when residing in a disk file. \r\n is used with Microsoft system software on PCs, while \n is used on UNIX systems.

Suppose that we wish to read and write sets of text lines sequentially, for example, reading all the lines in a file, one after another, or writing to a file in a similar way.

One way to do this is illustrated in the following example. We set up our own file output buffer, and move characters from a passed-in String object directly to the buffer. We use the low-level FileOutputStream class to actually do the I/O; it has a write() method that takes a vector of bytes and outputs them to a file or to standard output.

We determine whether \r\n or just \n is needed on output, by looking at the system properties list. JDK 1.0 running on Windows NT has an anomaly or feature in the way that standard output is treated with respect to line delimiters, and so if output is to standard out it's treated differently.

This particular example, with the driver program below, runs about 5X faster than the equivalent using System.out.print(). The code for doing input of text lines is analogous.
        import java.io.*;

        class StdioOutput {
                private static final int BUFSIZ = 4096;
                private FileOutputStream fos;
                private byte buf[] = new byte[BUFSIZ];
                private int left;
                private int pos;
                private static boolean need_cr = false;

                // figure out whether we have \r or \r\n

                static {
                        String s = System.getProperty("line.separator");
                        need_cr = (s.length() >= 1 && s.charAt(0) == '\r');
                }

                // open a file

                public StdioOutput(String fn) throws IOException
                {
                        fos = new FileOutputStream(fn);
                        left = BUFSIZ;
                        pos = 0;
                }

                // open standard output

                public StdioOutput() throws IOException
                {
                        fos = new FileOutputStream(FileDescriptor.out);
                        left = BUFSIZ;
                        pos = 0;
                        need_cr = false;
                }

                // close a file

                public synchronized void close() throws IOException
                {
                        flush();
                        fos.close();
                        fos = null;
                }

                // flush output

                public synchronized void flush() throws IOException
                {
                        if (pos > 0)
                                fos.write(buf, 0, pos);
                        left = BUFSIZ;
                        pos = 0;
                }

                // output a character

                public synchronized void putc(int c) throws IOException
                {

                        // flush output buffer if needed

                        if (left <= 0)
                                flush();

                        // handle simple case

                        if (c != '\n' || !need_cr) {
                                left--;
                                buf[pos++] = (byte)c;
                        }

                        // handle \r\n

                        else {
                                left--;
                                buf[pos++] = '\r';
                                if (left <= 0)
                                        flush();
                                left--;
                                buf[pos++] = '\n';
                        }
                }

                // output a line

                public synchronized void putline(String s) throws IOException
                {
                        int len = (s == null ? 0 : s.length());

                        // empty string

                        if (len < 1)
                                return;

                        // whole string will fit in buffer

                        if (len + 1 <= left) {
                                if (len >= 2) {
                                        s.getBytes(0, len - 1, buf, pos);
                                        pos += len - 1;
                                        left -= len - 1;
                                }
                                putc(s.charAt(len - 1));
                        }

                        // whole string won't fit, do a character at a time

                        else {
                                for (int i = 0; i < len; i++)
                                        putc(s.charAt(i));
                        }
                }
        }

        public class testio2 {
                public static void main(String args[])
                {
                        StdioOutput fout = null;
                        String s;

                        try {
                                fout = new StdioOutput();
                        }
                        catch (Throwable e) {
                                System.err.println("* file opening error *");
                        }

                        try {
                                int N = 10000;
                                for (int i = 1; i <= N; i++)
        //                              System.out.print("xxxxxxxxxxxxxxx\n");
                                        fout.putline("xxxxxxxxxxxxxxx\n");
                        }
                        catch (Throwable e) {
                                System.err.println("*** file I/O error ***");
                        }

                        try {
                                fout.close();
                        }

                        catch (Throwable e) {
                                System.err.println("* file closing error *");
                        }
                }
        }



Managing Directories

In the last issue we illustrated a way of invoking subprograms from within Java, and gave an example of listing the contents of a directory using the command "ls". Someone pointed out that this example is a bit misleading, because "ls" is unique to UNIX systems and because there are portable Java library techniques for achieving the same end.

To illustrate this point, here is a bit of Java code that lists the contents of a directory in a portable way, using the java.io.File class:
        import java.io.*;

        public class dir {

                public static void main(String args[])
                {
                        File f = new File(".");

                        String lst[] = f.list();

                        for (int i = 0; i < lst.length; i++)
                                System.out.println(lst[i]);
                }

        }

We create a File object based on the current directory, and then retrieve a vector of Strings that name the files found in that directory.

The File class has methods for checking for the existence and attributes of a file, such as whether it can be read or written and whether it's a directory. It's also possible to filter the names returned by list() in an arbitrary user-defined way, using the FileNameFilter interface. File system attributes like filename and pathname separators are queryable as well.


Invoke Subprograms

It's often the case that when writing programs, you'd like to invoke another program from within the first and send it input and get output from it. How might this be done in Java? A simple example that runs the UNIX program "ls" to retrieve a listing of files in the current directory looks like this:
        import java.io.*;

        public class test1 {

                public static void main(String args[])
                {
                        try {
                                Process cp = Runtime.getRuntime().exec("ls");
                                DataInputStream d =
                                    new DataInputStream(cp.getInputStream());
                                String line = null;
                                while ((line = d.readLine()) != null)
                                        System.out.println(line);
                        }
                        catch (Throwable e) {
                        }
                }

        }

The call to exec() starts the process running, and returns a Process object. Then we query the Process object to get a buffered input stream that is connected to the output of the child process. We then can simply iterate over this stream, reading lines in turn, that are the output of ls. In a similar way, it's possible to send input to the child process or capture its error output.

The Process class has several additional methods available for controlling processes:
        waitFor()       wait for the child process to complete

        exitValue()     return the exit value for the process

        destroy()       kill the process

There is also a variant of exec() that supports passing of environment variables to the child process.


Enums

In C++ there is a facility known as enumerations or enumerated types that can be used to represent a set of integral values:
        enum Color {CO_R = 1, CO_G = 2, CO_B = 3};

After this declaration, Color can be used as a type (including for function overloading purposes), and values like CO_R can be used wherever integral constants would be used. Type checking is done, so that for example:
        Color c = CO_R;

        c = 37;

is invalid.

Java does not have enumerations. One way to simulate them is simply by defining constants in a class:
        public class Color {
                public static final byte CO_R = 1;
                public static final byte CO_G = 2;
                public static final byte CO_B = 3;
        };

public means that these values are accessible to all, static means that they're shared across all object instances, final means that they're immutable once set, and byte means that they're represented in bytes in the virtual Java machine.

Once a class like this is set up, you can say things like:
        byte b = Color.CO_G;

But notice that this simulation is only a simulation. There's nothing to stop me from saying:
        byte b = Color.CO_R;
        b = 29;

and thereby introduce an invalid color value. A solution to this problem would be to define Color as a "real" class, that represents the actual current value of an enumeration:
        public class Color {
                private byte value = 0;
                public static final byte CO_R = 1;
                public static final byte CO_G = 2;
                public static final byte CO_B = 3;
                public Color(byte b)
                {
                        if (b == CO_R || b == CO_G || b == CO_B)
                                value = b;
                        else
                                throw new IllegalArgumentException();
                }
                public byte getvalue()
                {
                        return value;
                }
        }

This approach works, but can be cumbersome to use. However, enums, like other language features, add to the total complexity and implementation cost of a language, and leaving them out of Java is a reasonable design tradeoff to make.


JavaDoc

You may have heard of the term "JavaDoc" in relation to Java. What is this? JavaDoc is a tool that comes with the Java Development Kit. It's used for preparing HTML (the language of the Web) documentation for Java classes. That is, it generates HTML code that documents a class or package (set of related classes), including their methods, interfaces, exceptions, class hierarchy, and so on.

JavaDoc extracts structured comments from a Java source file. For example:
        /**
         * Create a hash table.
         *
         * @param       sz initial table size in hash slots (>= 1)
         * @param       load_factor (average elements per slot)
         *              (0.25 - 10.0)
         * @param       growth_factor (how much to grow the table
         *              when load factor is exceeded) (1.1 - 2.0)
         * @exception   IllegalArgumentException for invalid arguments
         */

        public Hash(int sz, float load_factor, float growth_factor)
        {
                // stuff
        }

This is documentation for a constructor for a hash table class. JavaDoc keys off of "/**" and tags like "@param". Page 182 of David Flanagan's "Java in a Nutshell" (O'Reilly) describes the tags that can be used.

You can run JavaDoc on individual Java source files, or on whole packages. It generates a set of HTML files that can be used on a Web page or with a Web browser whether connected to the Web or not. The files have hyperlinks between related classes and methods, so that a user can navigate easily through the documentation.


Sorting

In the last issue we talked about sorting in Java and said that there's no approach to sorting that's really similar to qsort() in C/C++. A couple of people wrote to me about this and suggested a technique that does in fact have some similarities.

The idea is to write a sort method that accepts a Vector of Object references, along with a class object instance that is a wrapper for a compareTo() method as illustrated above. The sort routine will iterate over the vector and call out to the compare method to determine the ordering of any two objects. Specifically, this would look like:
        import java.util.Vector;

        // Orderable interface

        interface Orderable {
                // return < 0 if p1 < p2, 0 if equal, > 0 if p1 > p2
                public int compareTo(Object p1, Object p2);
        };

        // wrapper for a compareTo() method for ordering Strings

        class Ord implements Orderable {
                public int compareTo(Object p1, Object p2)
                {
                        return ((String)p1).compareTo(((String)p2));
                }
        }

        public class Sort {

                public static void sort(Vector v, Orderable or)
                {
                        if (v == null || or == null)
                                ; // give error of some kind

                        // get vector size

                        int n = v.size();

                        // sort

                        for (int i = 0; i < n - 1; i++) {
                                for (int j = i + 1; j < n; j++) {

                                        // do comparison

                                        if (or.compareTo(v.elementAt(i),
                                            v.elementAt(j)) > 0) {
                                                Object ti = v.elementAt(i);
                                                Object tj = v.elementAt(j);
                                                v.setElementAt(tj, i);
                                                v.setElementAt(ti, j);
                                        }
                                }
                        }
                }

                // driver program

                public static void main(String args[])
                {
                        Vector v = new Vector();
                        int N = 100;
                        int i = 0;

                        // add some strings

                        for (i = 0; i < N; i++)
                                v.addElement("xxx" + i);

                        // sort them

                        Sort.sort(v, new Ord());

                        // display the sorted list

                        for (i = 0; i < N; i++)
                                System.out.println((String)v.elementAt(i));
                }

        }

This code can be tuned in various ways (starting with the sort algorithm) but is illustrative of the technique. We can implement any sort strategy we want on a Vector of objects simply by changing the ordering method. For example, saying:
        class Ordrev implements Orderable {
                public int compareTo(Object p1, Object p2)
                {
                        return -((String)p1).compareTo(((String)p2));
                }
        }

        ...

        Sort.sort(v, new Ordrev());

will reverse the sorting order for Strings. In this particular example, Strings have a compareTo() method already defined, and we simply cast the Object references to Strings and call this method. Note that if the wrong compareTo() wrapper instance is used, then an illegal cast will be attempted, resulting in an exception being thrown. For example, the above case expects a String, and will generate an exception ("ClassCastException") if the objects we pass in are actually Integers. The "instanceof" operator can be used to help sort things out.

In production code we'd have Orderable defined in a separate source file. Ord might or might not be in its own file, depending on stylistic preferences. Ord is simply a wrapper for a particular compareTo() method. In C or C++ we would pass in a function pointer directly, but Java has no user-visible pointers and no global functions.

If we critique this approach and compare it to qsort(), there are some notable differences and some similarities:
        1.  This approach is higher-level than qsort(), because it
        doesn't fool with pointers and sizes of objects and so on.

        2.  This approach cannot be used to directly sort vectors of
        fundamental data types like int or double.  They must be
        sorted using object wrappers.

        3.  Both approaches require calling out to a function or
        method that is used to order elements.  Such calls are
        expensive.

        4.  This approach has some overhead in accessing and setting
        Vector element slots.  There is method call overhead, as well
        as the subscript range checking done each time within a method
        like elementAt().

It's possible to write a similar type of method for doing binary searches, kind of like bsearch() in the C library.


Random Numbers

Random numbers are useful in many contexts in programming. One common use is in games, and another is for testing program algorithms such as those used in searching or sorting.

Java has random number support in the library class java.util.Random. Basic use is:
        import java.util.*;

        Random rn = new Random();

        ...

        int r = rn.nextInt();           // 32-bit random number

        double d = rn.nextDouble();     // random value in range 0.0 - 1.0

The random number generation algorithm is based on the linear congruential method (see for example Chapter 3 in Volume 2 of Knuth's "Art of Computer Programming"). This method has a starting value (a "seed"), and each value of the sequence is generated from the last. Whether such a stream of random numbers are in fact truly random is an interesting question beyond the scope of this discussion. If you're interested in that question you might consult Knuth's book.

If the default Random() constructor is used, the random number generator is seeded from the current time of day. You can also specify your own seed:
        Random rn = new Random(1234);

to generate a repeatable sequence of random numbers.

To show how random numbers might be used, here is a class Test that will generate random numbers in a range using the rand() method, or generate random strings composed of characters 'a' ... 'z'.
        import java.util.*;

        public class Test {

                private static Random rn = new Random();

                private Test()
                {
                }

                public static int rand(int lo, int hi)
                {
                        int n = hi - lo + 1;
                        int i = rn.nextInt() % n;
                        if (i < 0)
                                i = -i;
                        return lo + i;
                }

                public static String randomstring(int lo, int hi)
                {
                        int n = rand(lo, hi);
                        byte b[] = new byte[n];
                        for (int i = 0; i < n; i++)
                                b[i] = (byte)rand('a', 'z');
                        return new String(b, 0);
                }

                public static String randomstring()
                {
                        return randomstring(5, 25);
                }
        }

Actual random numbers are obtained using nextInt(), and then knocked down to the relevant range using the modulo ("%") operator.

Note that Test is simply a packaging vehicle with all of the methods as class methods ("static"). To obtain a random String of between 10 and 40 characters, you would say:
        String s = Test.randomstring(10, 40);



Linked List

Java has no user-visible pointers, so how would you do a linked list?
Each element needs to point to the next one, doesn't it?

Well, fortunately there is a way, illustrated using this brief example:
        // source file link.java

        public class link {
                public int value;              // value of element
                public link next;              // reference to next

                // constructor
                public link(int n, link ln)
                {
                        value = n;
                        next = ln;
                }

                public static void main(String args[])
                {
                        // initialize list head
                        link head = null;

                        // add some entries to list
                        for (int i = 1; i <= 10; i++)
                                head = new link(i, head);

                        // dump out entries
                        link p = head;
                        while (p != null) {
                                System.out.println(p.value);
                                p = p.next;
                        }
                }
        }

Java does not have pointers, but instead uses implicit references. A line like:
        link next;

does not actually declare an object instance of class link, but rather a reference to an object instance. The line:
        head = new link(i, head);

creates a new element for the list, sets its value, and then sets the object reference in "next" to point at the old list head (this approach means that the last element inserted will be at the head of the list). Saying:
        p = p.next;

simply picks up the "next" reference from the current node and makes it the current element being worked on.

When we're done using this list, we can simply leave the list with all its elements lying around -- garbage collection will eventually reclaim it.

If what you really want to do in a Java application is manage a list of numbers, there are higher-level techniques in the language and library (such as the Vector class) for doing so more cleanly than the approach illustrated here. This example shows some of what can be done underneath to implement the higher-level schemes.


Chars, Unicode and File I/O

In the last section we mentioned that a char in Java is 16 bits, stored as two bytes. The high byte typically is 0, and various of the Java library classes and methods allow one to specify the high byte. Here's an example of byte and character I/O that illustrates some of these points, in a file "uni.java":
        import java.io.*;

        public class uni {
                public static void main(String args[])
                {
                        InputStream istr = null;

                        try {
                                istr = new FileInputStream("testfile");
                        }
                        catch (FileNotFoundException e) {
                                System.err.println("*** file not found ***");
                                System.exit(1);
                        }

                        try {
                                int b;
                                String s = "";
                                while ((b = istr.read()) != -1) {
                                        s += (char)b;
                                }
                                System.out.print(s);
                        }
                        catch (IOException e) {
                        }

                        System.exit(0);
                }
        }

In this example, we attempt to open a file input stream to an input file "testfile", catching an exception and bailing out if the open fails (more about exceptions below). Note that we don't close the file explicitly. This is done by something akin to a C++ destructor, a method called finalize() that is invoked when garbage collection is done. We will talk about this area at some point; the semantics of resource cleanup and freeing are different in Java because of delayed object destruction.

Then we read bytes from the file using the read() method. The bytes are returned as ints, so that -1 can be used to indicate end of file (C has a similar trick with EOF). We take each int (byte) and cast it to a character and append it to a String object that we'd initialized to the empty string. Finally, we print the string.

A String object has a sequence of characters in it, and we have converted the input bytes that were read into characters and shoved them into the string. Since characters are Unicode, we have converted a sequence of input bytes into Unicode.

But it's not quite this easy. In casting to a character, there is the implicit supplying of a 0 to fill the high byte of the character, resulting in code that's not very portable. A better way to express the line:
        s += (char)b;

would be:
        byte x[] = {(byte)b};
        s += new String(x, 0);

In other words, build a vector of bytes and construct a String from them, with the high byte fill value explicitly specified.

We will be saying more about Java I/O in the future. The Java library has a variety of classes and methods for dealing with input and output of various types. The I/O example shown above illustrates a way of doing low-level input. There are higher-level mechanisms available in the library.

A WAY OF DOING CLASS INITIALIZATION

In C++ one can use constructors to initialize class object instances when they're created, and employ static data members that are initialized when the program starts. But what if you'd like some code to be executed once for a given class, to kind of set things up for the class? One way of doing this in Java is to say:
        public class A {
                static {
                        System.out.println("got to static initialization");
                }
                public static void main(String args[])
                {
                        System.out.println("start of main()");
                        A c1 = new A();
                        A c2 = new A();
                }
        }

No matter how many instances of objects of class A are created, the block of code at the top will be executed only one time. It serves as a hook to do class setup at the beginning of execution.


What Happens when you output a character ?

The technique shown in the previous section has one very important use. When you say:
        System.out.println("x");

what happens? It's interesting to trace through the sequence of operations used to output a character.

In the first place, System is a class defined in the Java library. It is a wrapper class that you do not actually create object instances of, nor may you derive from the System class, because it is declared as "final". In C++ such a class is sometimes referred to as a "static global class".

System.out is defined as:
        public static PrintStream out;

meaning that it's available to all and that there is only one object instance of PrintStream for "out". This PrintStream stream corresponds to standard output, kind of like file descriptor 1 in UNIX, stdout in C, or cout in C++. Similar streams are established for input and standard error output.

The output stream is initialized via a static initialization block of the type illustrated above. The actual code is:
        out = new
		      PrintStream( new BufferedOutputStream( new FileOutputStream( FileDescriptor.out ), 128 ), true );

This is a mouthful that says that a PrintStream is based on a BufferedOutputStream (with a buffer 128 long) which is based on a FileOutputStream with a specified file descriptor, and that output is line buffered.

Saying:
        System.out.println("xxx");

means that you're invoking the println(String) method for a PrintStream. Doing so immediately results in the sequence:
        PrintStream.print("xxx");
        PrintStream.write('\n');

PrintStream.print("xxx") contains a loop that iterates over the characters in the String ("xxx" is a String, not a vector of characters) calling PrintStream.write() for each. PrintStream.write() calls out.write(), implementing line buffering as it goes.

What is out.write()? When the output stream was initialized, we created a PrintStream object and said that it should be based on a BufferedOutputStream. "out" is an instance variable of a class FilterOutputStream from which PrintStream derives ("extends"), and out is set to reference a BufferedOutputStream object. In a similar way, BufferedOutputStream is based on FileOutputStream.

out.write() in BufferedOutputStream collects characters into a buffer (specified in the creation line illustrated above). When the buffer becomes full, out.flush() is called. This results in a different write() being called in the FileOutputStream package. It writes a sequence of bytes to the file descriptor specified when the stream was created. This last method is native, that is, is implemented in C or assembly language and not in Java code itself.

This approach to I/O is quite flexible and powerful, and names like "stream nesting" and "stream filtering" are used to describe it. It's not a terribly efficient approach, however, especially since Java itself is interpreted and many of the higher layers of the system are written in Java itself.

One other note: when trying to figure out just what methods are called in an example like the one in this section, it's helpful to use the profiling feature of JDK:
        $ java -prof xxx

This shows called methods, who called them, and how many times they were called.


Temporary Files

In programming applications you often need to use temporary files -- files that are created during program execution to hold transient information.
A typical case is a language compiler that uses several passes (such as preprocessing or assembly) with temporary files used to hold the output of the previous pass.
In some cases, you could use memory instead of disk files, but you can't always assume that the required amount of memory will be available.
One feature in JDK(tm) 1.2 is the ability to create temporary files. These files are created in a specified directory or in the default system temporary directory (such as C:\TEMP on Windows systems).
The temporary name is something like the following:

t:\tmp\tmp-21885.tmp

The same name is not returned twice during the lifetime of the Java virtual machine.
The returned temporary file is in a File object and can be used like any other file.
Note: With Unix, you may find that your input file has to also reside in the same file system where the temporary files are stored.
The renameTo method cannot rename files across file systems.
Here is an example of using temporary files to convert an input file to upper case:
import java.io.*;

public class upper
{
	public static void main(String args[])
	{
		// check command-line argument

		if (args.length != 1) {
			System.err.println("usage: upper file");
			System.exit(1);
		}
		String in_file = args[0];

		try {
			// create temporary and mark "delete on exit"

			File tmpf = File.createTempFile("tmp");
			tmpf.deleteOnExit();
			System.err.println("temp file = " + tmpf);

			// copy to temporary file,
			// converting to upper case
			File           inf = new File(in_file);
			FileReader     fr  = new FileReader(in_file); BufferedReader br = new BufferedReader(fr);
			FileWriter     fw  = new FileWriter(tmpf.getPath());
			BufferedWriter bw  = new BufferedWriter(fw);
			String s = null;
			while ((s = br.readLine()) != null) {
				s = s.toUpperCase();
				bw.write(s, 0, s.length());
				bw.newLine();
			}
			br.close();
			bw.close();

			// rename temporary file back to original file
			if (!inf.delete() || !tmpf.renameTo(inf)) System.err.println("rename failed");
		}
		catch (IOException e) {
			System.err.println(e);
		}
	}
}


The input file is copied to the temporary file, and the file contents are converted to upper case.
The temporary file is then renamed back to the input file.
JDK 1.2 also provides a mechanism whereby files can be marked for "delete on exit." That is, when the Java virtual machine exits, the file is deleted.
An aspect worth noting in the above program is that this feature handles the case where the temporary file is created, and then an error occurs (for example, the input file does not exist).
The delete-on-exit feature guarantees that the temporary file is deleted in the case of abnormal program termination.

resource Bundles

One of the strengths of the Java programming language is the variety of language and API mechanisms that promote internationalization.
For example, Unicode characters (16 bits) support more character sets than the typical 8-bit character set used in other languages.

One of the most important of these mechanisms is known as "resource bundles."
A resource bundle contains locale-specific objects, for example strings representing messages to be displayed in your application.
The idea is to load a specific bundle of resources, based on a particular locale.

To show how this mechanism works, here's a short example that retrieves and displays the phrase for "good morning" in two different languages:
# German greeting file (greet_de.properties)

morn=Guten Morgen

# English greeting file (greet_en.properties)

morn=Good morning

The above lines make up two text files, greet_de.properties and greet_en.properties.
These are simple resource bundles.

The following program accesses the resource bundles:
import java.util.*;

public class bundle {
	public static String getGreet(String f, String key, Locale lc)
	{
		String s = null;
		try {
			ResourceBundle rb =
			ResourceBundle.getBundle(f, lc);
			s = rb.getString(key);
		}
		catch (MissingResourceException e) {
			s = null;
		}
		return s;
	}

	public static void main(String args[])
	{
		String fn = "greet";
		String mornkey = "morn";
		Locale ger = Locale.GERMAN;
		Locale eng = Locale.ENGLISH;

		System.out.println("German locale = " + ger);
		System.out.println("English locale = " + eng);

		System.out.println(getGreet(fn, mornkey, ger));
		System.out.println(getGreet(fn, mornkey, eng));
	}
}

The idea is that ResourceBundle.getBundle looks up a particular bundle, based on the locale name ("de" or "en").
The bundles in this example are property files (see java.util.Properties), with "key=value" pairs in them, and the files are located in the current directory.
A particular bundle is retrieved based on the locale, and then a specific key is looked up, and the corresponding value returned.
Note that there are a number of additional aspects to resource bundle naming and lookup that you should acquaint yourself with if you're concerned with internationalization issues.
Resource bundles are commonly used to represent a collection of message strings, but other types of entities, such as icons, can also be stored in bundles.

The output of the program is:
German locale = de
English locale = en
Guten Morgen
Good morning

Finally, if you program your application's message display features in terms of locales and resource bundles, as this example illustrates, then you have taken an important step toward internationalizing your program.

JAR archiving

Have you tried using JAR files for archiving? You may have heard of a UNIX tool called "tar," or tape archiver, that's used to group files together for backup purposes. In the Java Development Kit 1.1 and later releases, there's a similar facility known as "jar," or Java Archiver. Here's a way to use this tool.

A JAR archive is created with the following:
        $ jar cf archive.jar file1 file2 ...

After you create the archive, you can list the contents with:
        $ jar tf archive.jar

and files can be extracted with the following:
        $ jar xf archive.jar [file1 file2 ...]

Why is the JAR facility important? After all, various ZIP tool versions exist for archiving and compressing files. One important use of JAR is for bundling Java .class files. A group of such files could constitute a Java package or library. For example, with Windows 95 or NT you might say:
        CLASSPATH="lib1.jar;lib2.jar;"

Another very important JAR use is for optimizing applet loading. Consider this example with a simple applet:
        // applet.java
        import java.awt.*;
        import java.applet.*;

        public class applet extends Applet {
            public void paint(Graphics g)
            {
                String s = Message.getIntro(getParameter("intro"));
                g.drawString(s, 25, 25);
            }
        }

that accesses an auxiliary class:
        // Message.java
        public class Message {
            public static String getIntro(String t)
            {
                if (t != null)
                    return t;
                else
                    return "Hello world!";
            }
        }

You can invoke this applet with some HTML code, such as:
        <html>
        <head><title>Hello World Example Applet </title>
        <body>
        <applet code="applet.class" archive="applet.jar" width=150
            height=150>
        <param name="intro" value="good morning">
        </body>
        </html>

Note the "archive" attribute. Without this setting, each subsidiary class that's loaded, such as Message, would involve a separate request to the server holding the HTML page. But with the JAR file, the various .class files can be downloaded more efficiently.

In this example, you prepare archive.jar with the following:
        $ javac applet.java
        $ jar cf applet.jar *.class

that is, construct the JAR file from all of the .class files.

A final note: JAR files are also used with JavaBeans.


Printing in Java

JDKTM 1.1 provides a standard way to print and improves on JDK 1.0 printing.

You print via the Abstract Window Toolkit (AWT). A simple example for printing a filled-in oval looks like this:
   import java.awt.*;

   public class print {

      public static void main(String args[])
      {
         Frame f = new Frame("test");
         f.pack();

         PrintJob pj =
            f.getToolkit().getPrintJob(f, "print1", null);

         if (pj != null) {
            Graphics g = pj.getGraphics();

            g.fillOval(5, 5, 150, 100);

            g.dispose();

            pj.end();
         }
         System.exit(0);
      }
   }

This example is a standalone Java program that creates an AWT frame, a top-level GUI component for running an application. The program next retrieves the toolkit for the frame. The toolkit for the AWT is the interface between the abstract window layer and an actual windowing implementation such as Windows 95 or X Windows.

Once you create the toolkit, you can initiate a print job via getPrintJob, which causes a window to pop up on the screen asking the user for information about which printer is being used, the number of copies to print, and so on. This process is similar to printing in conventional Windows applications.

Given a PrintJob object, you can obtain a graphics context and draw to it. Such drawing, using normal graphics primitives such as fillOval, goes to the printer instead of the screen. Calling dispose on the graphics context object sends the page to the printer, and the print job is terminated by calling end.

If you're using your own custom AWT components, you can use the paint methods you define for printing without change--by passing them the graphics context returned by getGraphics. But if you want different behavior when you print, specialized methods can also be defined for components as necessary.

-- Printing from applets

The example given above is a standalone Java program. But what about printing from applets? The Java security system contains a feature that may lock out an applet from initiating its own print job, requiring that the initiation be done via a Web browser or applet viewer. The security area is in a state of flux at present, and your experiences with this process may be different.

Finally, another less portable approach to printing text is to open the special device file that represents the printer, and do conventional file I/O to that file. For example, "lpt1" can be used for this purpose with Windows systems, and "/dev/lp" can be used with UNIX.


Menu Shortcuts

The ability to specify menu shortcuts is one of the features in JDKTM 1.1-- where menu choices can be selected via the keyboard instead of with the mouse.
For example:
   import java.awt.*;
   import java.awt.event.*;

   public class menu implements ActionListener {
      public void actionPerformed(ActionEvent e)
      {
         String lab = ((MenuItem)e.getSource()).getLabel();
         System.out.println("label = " + lab);
         if(lab.equals("Exit"))
         {
            System.exit(0);
         }
      }

      public static void main(String args[])
      {
         Frame f = new Frame("testing");

         Menu m = new Menu("File");

         menu acl = new menu();

         MenuItem mi1 = new MenuItem("Open");
         mi1.addActionListener(acl);
         m.add(mi1);

         MenuItem mi2 = new MenuItem("Save");
         mi2.addActionListener(acl);
         m.add(mi2);

         MenuShortcut ms3 = new MenuShortcut(KeyEvent.VK_E);
         MenuItem mi3 = new MenuItem("Exit", ms3);
         mi3.addActionListener(acl);
         m.add(mi3);

         MenuBar mb = new MenuBar();
         mb.add(m);

         f.setMenuBar(mb);
         f.setSize(200, 200);
         f.setVisible(true);
      }

   }

The example sets up a frame, which is a top-level application window. The frame contains a menu bar, and the menu bar contains a single pull-down menu named "File." The menu offers choices for Open, Save, and Exit, with Exit having a keyboard shortcut set up for it that specifies the virtual key code "E."

How the shortcut gets invoked varies, depending on the platform in question. For example, with Windows you use Ctrl-E so that when a user types Ctrl-E within the window containing the menu bar, the Exit command is invoked.

One last thing: this example doesn't actually have a command structure set up for it, but instead invokes actionPerformed to demonstrate that the command processing structure is in place.


Command Dispatching

In C and C++, programmers often use a set of global functions and function pointers to represent a series of commands or operations and then dispatch to them via a table. For example:
   #include 

   void func1() {printf("func1\n");}

   void func2() {printf("func2\n");}

   typedef void (*fp)(void);

   fp funcs[] = {&func1, &func2, 0};

   int main()
   {
      int i = 0;

      while (funcs[i])
         funcs[i++]();
      return 0;
   }

Java, though, does things differently. It doesn't use pointers and doesn't have global functions. Instead, Java uses a technique of creating and referencing object instances through which the objects call a method known to be implemented by an object of a given type.

How does the technique work in practice? Consider this example:
   interface Action {
      public void doit();
   }

   class func1 implements Action {
      public void doit() {System.out.println("func1");}
   }

   class func2 implements Action {
      public void doit() {System.out.println("func2");}
   }

   public class call {
      private static Action alist[] = {
         new func1(),
         new func2()
      };

      public static void main(String args[])
      {
         for (int i = 0; i < alist.length; i++)
            alist[i].doit();
      }

   }

In this example, an interface Action is defined, and any class that implements the interface must define a method doit (this notion, by the way, is basic to the meaning of interfaces). Objects of the class can be referred to with a reference to the implemented interface name type, so that a reference of type Action can refer to an object of a class that implements Action.

In C++ programming Action would be a base class, with func1 and func2 being derived classes, and object manipulation would be performed via a base class pointer. With Java, an Action reference supports a similar manipulation, although Action is not a superclass of func1 and func2.

The Java technique given here sometimes goes by the name "method wrappers," and is quite different from the C/C++ approach. There are some tradeoffs, of course, as to which approach works the best in a given situation.

A second example

Another example of the method wrappers technique is used fairly often in the Abstract Windowing Toolkit (AWT). Consider the following:
   import java.awt.*;
   import java.awt.event.*;

   public class buttonlistener implements ActionListener {

      public void actionPerformed(ActionEvent e)
      {
         System.exit(0);
      }

      public static void main(String args[])
      {
         Frame f = new Frame("testing");
         Button b = new Button("OK");
         b.addActionListener(new buttonlistener());
         f.add(b);
         f.pack();
         f.setVisible(true);
      }

   }

The example creates a frame and adds an OK button to it. When the button is selected, the program terminates. An action listener is added to the button. The action listener is guaranteed to implement a method actionPerformed, because an instance of buttonlistener implements the ActionListener interface. Selecting the button results in a call to the action listener for the button.

Finally, the listeners concept is extremely important in the AWT. The underlying basis of listeners involves implementing specified interfaces and thereby guaranteeing that a listener will be able to respond to a particular known method invocation on it.


Performances

In this section the performances tips.

Garbage and Null

Here's a performance tip: garbage collection and setting to null. Java uses garbage collection, or reclaiming no-longer-used storage, rather than requiring you to explicitly manage storage. Garbage collection is automatic, but sometimes there are ways to help it out. Imagine a case where you're managing a stack of Object references:
        public class Stack {
            private static final int MAXLEN = 10;
            private Object stk[] = new Object[MAXLEN];
            private int stkp = -1;

            public void push(Object p) {stk[++stkp] = p;}

            public Object pop() {return stk[stkp--];}
        }

Now consider a case where the stack has two elements on it, and you pop one of them. At this point stk[0] will have a valid element in it, and stk[1] will have the element just popped. That is, stk[1] will have a reference to an Object, which could be a reference to anything, including a large data structure of many thousands of bytes. In such a case, this data structure cannot be garbage collected, even though it may no longer be in use.

To remedy this problem, you can rewrite pop like so:
        public Object pop()
        {
            Object p = stk[stkp];
            stk[stkp--] = null;
            return p;
        }

You haven't nullified the Object itself, just a reference to it that's no longer valid. The Stack object itself may have a long lifetime, and rewriting the pop method in this way helps ensure that garbage collection gets done in a timely fashion.


Examples


Example 1

Here is a longer example of a complete Java program (not an applet). This program does simple expression evaluation, so for example, input of:
        (1 + 2) * (3 + 4)

yields a value of 21.

If you're not familiar with this sort of programming, similar to what is found in language compilers themselves, a brief explanation is in order. The program takes input and splits it into what are called tokens, logical chunks of input. For the input above, the tokens are:
        (
        1
        +
        2
        )
        *
        (
        3
        +
        4
        )

and the white space is elided. Then the program tries to make sense of the stream of input tokens. It implicitly applies a grammar:
        expr -> term | expr [+-] term
        term -> fact | term [*/] fact
        fact -> number | ( expr )

Don't worry too much if you don't understand this. It's a way of describing the structure of input. You can think of it as a way of converting an input expression into the Reverse Polish Notation that some older calculators used to use.

Here is the actual program, in a file "calc.java". We will have more to say about this program in the next section below. Annotations are given in /* */ comments, while regular program comments use //. (Note: we're not trying to do anything fancy with comments for JavaDoc purposes, a subject to be presented another time).
        import java.io.*;

        public class calc {
                private String in_line;                 // input line
                private int in_len;                     // input line length
                private int currpos;                    // position in line
        		// The input line, its length, and the current position in it.
                private byte curr_tok;                  // current token
                private int val_token;                  // value if num
        		// The current token and its value if it's a number.
                private boolean had_err;                // error in parsing
        		// Used to record whether a parsing error occurred on the input.
        		// Exception handling could also be used for this purpose, and is used for another type of error (divide by 0).
                private static final byte T_NUM = 1;    // token values
                private static final byte T_LP = 2;
                private static final byte T_RP = 3;
                private static final byte T_PLUS = 4;
                private static final byte T_MINUS = 5;
                private static final byte T_MUL = 6;
                private static final byte T_DIV = 7;
                private static final byte T_EOF = 8;
                private static final byte T_BAD = 9;
        /*
        Possible token values.  These are private (available only to the
        class), static (shared across all class object instances), and
        final (constant).
        */
                // get next token from input line
                private void get_token()
                {
                        // skip whitespace

                        while (currpos < in_len) {
                                char cc = in_line.charAt(currpos);
								// in_line.charAt(currpos) returns the current character from the string.
                                if (cc != ' ' && cc != '\t')
                                        break;
                                currpos++;
                        }

                        // at end of line?

                        if (currpos >= in_len) {
                                curr_tok = T_EOF;
                                return;
                        }

                        // grab token

                        char cc = in_line.charAt(currpos);
                        currpos++;
                        if (cc == '+' || cc == '-')
                                curr_tok = (cc == '+' ? T_PLUS : T_MINUS);
                        else if (cc == '*' || cc == '/')
                                curr_tok = (cc == '*' ? T_MUL : T_DIV);
                        else if (cc == '(' || cc == ')')
                                curr_tok = (cc == '(' ? T_LP : T_RP);
        /*
        This block of code could also be handled via a switch statement
        or in a couple of other ways.
        */
                        else if (Character.isDigit(cc)) {
                                int n = Character.digit(cc, 10);
                                while (currpos < in_len) {
                                        cc = in_line.charAt(currpos);
                                        if (!Character.isDigit(cc))
                                                break;
                                        currpos++;
                                        n = n * 10 + Character.digit(cc, 10);
                                }
                                val_token = n;
                                curr_tok = T_NUM;
        /*
        The above code grabs a number.  Character.isDigit(char) is a method
        of the character class that returns a boolean if the character is a
        digit.  Character.digit(char, int) converts a character to a number
        for a given number base (10 in this case).

        The primitive types like char have corresponding class types, though
        you cannot call a method directly on a primitive type object.  You
        must instead use the techniques illustrated here.
        */
                        }
                        else {
                                curr_tok = T_BAD;
                        }
        		// The case where the token can't be recognized.
                }

                // constructor, used to set up the input line
                public calc(String s)
                {
                        in_line = s;
                        in_len = in_line.length();
                        currpos = 0;
                        had_err = false;
                        get_token();
                }
        /*
        The constructor sets up an object instance for doing calculations.  We
        set up the input line, clear any error condition, and grab the first
        token.
        */
                // addition and subtraction
                private double expr()
                {
                        // get first term

                        double d = term();

                        // additional terms?

                        while (curr_tok == T_PLUS || curr_tok == T_MINUS) {
                                byte t = curr_tok;
                                get_token();
                                if (t == T_PLUS)
                                        d += term();
                                else
                                        d -= term();
                        }
                        return d;
                }
        /*
        This and the next method are similar.  They grab a term() or fact()
        and then check to see if there are more of them.  This matches input
        like:

                1 + 2 + 3 + 4 ...

        As each token is consumed, another one is grabbed.
        */
                // multiplication and division
                private double term()
                {
                        // get first factor

                        double d = fact();

                        // additional factors?

                        while (curr_tok == T_MUL || curr_tok == T_DIV) {
                                byte t = curr_tok;
                                get_token();
                                if (t == T_MUL)
                                        d *= fact();
                                else {
                                        double d2 = fact();
                                        if (d2 == 0.0 && !had_err)
                                               throw new ArithmeticException();
                                        d /= d2;
        /*
        This code is similar to expr() above but we check for division by 0
        and throw an arithmetic exception if we find it.  We will see below
        where this exception is handled.
        */
                                }
                        }
                        return d;
                }

                // numbers and parentheses
                private double fact()
                {
                        double d;

                        // numbers
                        if (curr_tok == T_NUM) {
                                d = val_token;
                                get_token();
                        }
        				//  If a number, retrieve the value stored in val_token.
                        // parentheses
                        else if (curr_tok == T_LP) {
                                get_token();
                                d = expr();
                                if (curr_tok != T_RP) {
                                        had_err = true;
                                        d = 0.0;
                                }
                                get_token();
                        }
        /*
        If (, then grab the expression inside and check for ).  If not found,
        record that we had an error.  We could also throw an exception at this
        point.
        */
                        // garbage

                        else {
                                had_err = true;
                                get_token();
                                d = 0.0;
                        }
        				// The token was not recognized, so we have bad input.
                        return d;
                }

                // parse input and get and print value
                public String get_value()
                {
                        double d;

                        try {
                                d = expr();
                        }
                        catch (ArithmeticException ae) {
                                return new String("*** divide by 0 ***");
                        }
                        if (had_err || curr_tok != T_EOF)
                                return new String("*** syntax error ***");
                        else
                                return String.valueOf(d);
        /*
        Here is where we actually try to get the value of the expression.  We
        convert its value back to a String for reasons of flexibility in
        handling error conditions.

        Division by 0 will result in an exception being thrown and caught
        here.

        If we encountered an error, or if we've not exhausted the input string
        (for example, for input "((0)))"), then we also flag an error.
        Otherwise, we return the string value of the double using the method
        String.valueOf(double).
        */
                }


                // get a line of input from the keyboard
                private static String getline()
                {
                        DataInput di = new DataInputStream(System.in);
                        String inp;

                        try {
                                inp = di.readLine();
                        }
                        catch (IOException ignored) {
                                inp = null;
                        }
                        // This is a wrapper function to get a line of input from the keyboard.
                        return inp;
                }

                // driver
                public static void main(String args[])
                {
                        String inp = "";

                        // command line arguments

                        if (args.length > 0) {
                                for (int i = 0; i < args.length; i++)
                                        inp = inp + args[i];
                                calc c = new calc(inp);
                                System.out.println(c.get_value());
        /*
        If there are command-line arguments, we will append them into one
        string using the "+" operator and then evaluate the value of the
        expression. args.length is the number of command-line arguments, and
        args[i] is the i-th argument.

        The line:

                calc c = new calc(inp);

        creates a new calc object and calls its constructor with inp as the
        String argument to the constructor.

        c.get_value() returns the expression value as a String.
        */
                        }

                        // no command line arguments, prompt user
                        else {
                                for (;;) {
                                        System.out.print("input string: ");
                                        System.out.flush();
        								// We flush output here because it's normally line buffered and we've not
        								// output a newline character.
                                        inp = getline();
                                        if (inp == null)
                                                break;
        								// End of input.
                                        calc c = new calc(inp);
                                        System.out.println(c.get_value());
                                }
                        }
                }
        }