Issue #011 November, 1996 Contents: Newsletter Index Java Language Specification Comparing C/C++ and Java Part 11 - Preprocessing Introduction to Applet Programming Part 7 - Animation Performance - Binary Search Class NEWSLETTER INDEX An index to all the Java and C++ newsletters can be found on the Web at: http://rainbow.rmi.net/~glenm The index will be updated as new issues come out. JAVA LANGUAGE SPECIFICATION This is the name of a recently-published book by Gosling, Joy, and Steele, published by Addison-Wesley. It's about 800 pages and costs around $35. There are about 450 pages on the language proper, and 300 on the core packages like java.lang, java.util, and java.io. Included is a LALR(1) grammar for the language. This is a good book if you're interested in the exact details of how the language and associated packages work. It's not a tutorial, and does go into a lot of depth about particular language features. COMPARING C/C++ AND JAVA PART 11 - PREPROCESSING C and C++ have a preprocessor that is run over source files before other processing. Java does not have a preprocessor. One use of the preprocessor is to define constants: #define N 79 In Java this can be accomplished by saying: public static final int N = 79; where "public" means that the constant is available to all, "static" means that it's shared by all object instances of a given class, and "final" means it cannot be changed after initialization. Another use of the preprocessor is to define macros: #define max(x, y) ((x) > (y) ? (x) : (y)) This is typically done for speed or readability. A good compiler reduces the need for this facility, by inline expanding short methods. This is an area of Java still in a state of flux, however. The preprocessor can be used to #include other files into a source file. Java packages and naming conventions and import directives (see newsletters #003, #004, and #005) mostly eliminate the need for #include. Finally, the preprocessor has directives like: #ifdef XXX stuff ... #endif to perform conditional compilation, typically on a per-platform basis. Java is a platform-independent language, and in theory such a directive is not needed. In practice, however, it would be useful to be able to do conditional compilation. For example, the AWT (Abstract Windowing Toolkit), may perform differently across platforms, due to the vagaries of the underlying window systems. There's nothing to stop you from using your own preprocessor or macro processor, but such an approach is not part of the official Java language. INTRODUCTION TO APPLET PROGRAMMING PART 7 - 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) { } } } } along with the HTML code that drives the applet: Interface to Animation Applet 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. PERFORMANCE - 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://rainbow.rmi.net/~glenm/javalib/index.html ACKNOWLEDGEMENTS Thanks to Jay Burgess, Thierry Ciot, Irv Kanode, Mike McCann, Mike Paluka, Srihari Sampathkumar, and Bob Shore 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: rmi.net /pub2/glenm/javalett or on the Web at: http://rainbow.rmi.net/~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: rmi.net /pub2/glenm/javalett (for back issues) Web: http://rainbow.rmi.net/~glenm