Issue #007
July, 1996


Contents:

Invoking Subprograms in Java
Comparing C/C++ to Java Part 7 - Destructors vs. Finalize
Free Java Library
Enums and Java
Introduction to Applet Programming Part 3 - Events


INVOKING SUBPROGRAMS IN JAVA

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.


COMPARING C/C++ TO JAVA PART 7 - DESTRUCTORS VS. FINALIZE

In C++ there is the notion of a destructor, a function called when a
class object instance goes out of scope.  For example:

        class A {
        public:
                A();
                ~A();
        };

        void f()
        {
                A a;
        }

When the function f() is entered, the constructor A::A() is called for
the local object a, and when f() is exited, the destructor A::~A() is
called in turn.

Java class objects do not behave in a similar way.  They are
dynamically allocated, at which point a constructor is run on the
object instance, and later garbage collected.

Java does not have any notion of a destructor method that is run when
an object instance is no longer valid.  But it does have a finalize()
method:

        protected void finalize() {}

that can be added to any class.  finalize() is called for an object
instance after that instance has been identified by the garbage
collector as no longer a valid object, that is, there are no remaining
references to it.  For example:

        public class test1 {

                public test1()
                {
                        System.out.println("call ctor");
                }

                protected void finalize()
                {
                        System.err.println("call finalize");
                }

                public static void f()
                {
                        test1 p = new test1();
                }

                public static void main(String args[])
                {
                        f();
                        System.gc();
                        System.runFinalization();
                }
        }

After the return from the f() call, there is an object instance that
can be garbage collected; there is no reference to the object we
created while inside of f().

System.gc() frees up objects and marks them as pending for
finalization to be done.  Actual finalization processing proceeds
asynchronously with the garbage collector, so to force finalization we
can call System.runFinalization().

Because of the way that finalize() methods work, you should use
caution in assuming that they can be used to reclaim valuable
resources such as UNIX file descriptors.  Also, you should insert a
line like:

        super.finalize();

at the end of a finalize() method, to call the corresponding method of
the superclass.


FREE JAVA LIBRARY

I have developed a Java library for managing collections of objects,
such as lists, stacks, sets, bitmaps, and trees.  If you are
interested in this library, please see the Web page:

        http://rmi.net/~glenm/javalib/index.html


ENUMS AND JAVA

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.


INTRODUCTION TO APPLET PROGRAMMING PART 3 - EVENTS

In previous issues we've talked about the basic protocols underlying
an applet and how graphical and text output is done.  With this issue
we'll start a discussion of input handling, and begin by talking about
events just a little bit.

Here is an applet that allows a user to do free drawing with the
mouse.  That is, whenever the mouse button is held down and the mouse
moved, a line will be drawn:

        import java.applet.*;
        import java.awt.*;

        public class Draw extends Applet {

                int prev_x = 0;
                int prev_y = 0;
                int color = 0;

                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();

                        switch (color) {
                                case 0:
                                        g.setColor(Color.red);
                                        break;
                                case 1:
                                        g.setColor(Color.green);
                                        break;
                                case 2:
                                        g.setColor(Color.blue);
                                        break;
                        }
                        if (++color > 2)
                                color = 0;

                        g.drawLine(prev_x, prev_y, x, y);
                        prev_x = x;
                        prev_y = y;
                        return true;
                }
        }

This applet can be invoked via the HTML code:

        <html>
        <head>
        <title>Interface to Draw Applet</title>
        </head>

        <body>

        <applet code="Draw.class" width=400 height=400></applet>

        </body>
        </html>

using the JDK AppletViewer program.

We've alternated the output color of the drawn line, as a means of
tying together some of the ideas from the last issue, and to better
illustrate what is happening.

mouseDown() is an applet method called by the system when the user
presses a mouse button.  It's passed a description of the event along
with an X,Y pair, and returns true if it handled the event, so that
the event will not be further processed.  In our example we simply
record the X,Y location where the event occurred.

mouseDrag() is a method called when the user drags the mouse with the
button down.  When this occurs, we switch colors and then draw a line
between the old position and the new one.  getGraphics() is a method
that returns a java.awt.Graphics object, that is used for line
drawing, image painting, and so on.

If you run the above applet, the colors will alternate very rapidly if
you move the mouse slowly, and alternate more slowly if you move the
mouse rapidly.  Why is this?  It has to do with polling of the mouse.
That is, the mouse's status is checked at regular intervals.  If the
mouse has moved a long ways in the poll interval, then the
single-color line segment will be longer than if the mouse had been
moved slowly.

We will be discussing events and input further in upcoming issues.


ACKNOWLEDGEMENTS

Thanks to Thierry Ciot, Irv Kanode, Mike Paluka, and Alan Saldanha for
help with proofreading.


SUBSCRIPTION INFORMATION / BACK ISSUES

To subscribe to the newsletter, send mail to majordomo@world.std.com
with this line as its message body:

subscribe java_letter

Back issues are available via FTP from:

        rmii.com /pub2/glenm/javalett

or on the Web at:

        http://www.rmii.com/~glenm

There is also a C++ newsletter.  To subscribe to it, say:

subscribe c_plus_plus

using the same majordomo@world.std.com address.

-------------------------

Copyright (c) 1996 Glen McCluskey.  All Rights Reserved.

This newsletter may be further distributed provided that it is copied
in its entirety, including the newsletter number at the top and the
copyright and contact information at the bottom.

Glen McCluskey & Associates
Professional Computer Consulting
Internet: glenm@glenmccl.com
Phone: (800) 722-1613 or (970) 490-2462
Fax: (970) 490-2463
FTP: rmii.com /pub2/glenm/javalett (for back issues)
Web: http://www.rmii.com/~glenm
