Issue #008 August, 1996 Contents: Managing Directories in Java Comparing C/C++ With Java Part 8 - Typedefs Introduction to Applet Programming Part 4 - Button Input Performance - charAt() MANAGING DIRECTORIES IN JAVA 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. COMPARING C/C++ WITH JAVA PART 8 - TYPEDEFS In C and C++, there is a facility known as typedefs, whereby you can define a name to represent a type. For example: typedef unsigned char* T; says that T is a type of pointer to unsigned character. Once a typedef has been specified, it can be used wherever a type is required, for example to declare a variable: void f() { T x; } Java has no typedefs, and it's interesting to consider this point. There are at least three reasons why typedefs are useful in C and C++. The first reason is to define types as an aid to portability. For example, a typedef may be defined to represent a 32-bit integer: typedef int INT32; // on workstation typedef long INT32; // on PC Integral types are of varying sizes in C and C++. This is not an issue in Java, where types are of uniform sizes. For example, an int is 32 bits, and a long 64. Another reason for typedefs in C is to introduce an alias for a structure name: struct A { int x; }; typedef struct A A; A x; In C++ and Java this usage is implicit in the language. Finally, typedefs are useful to represent complicated type combinations, as in: typedef unsigned long** T; which says that T is a pointer to a pointer to an unsigned long integer. Java has no-user visible pointers, nor does it have unsigned modifiers. So a typedef here doesn't buy very much. Typedefs are still useful simply for abstraction purposes, that is, as an abstract way of naming a type, for example "Age" instead of "int". But much of their usage in C and C++ doesn't apply in Java, and it's a reasonable decision to leave typedefs out of the language. INTRODUCTION TO APPLET PROGRAMMING PART 4 - 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: Interface to Text Applet 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. PERFORMANCE - CHARAT() Suppose that you have a need to find a character in a string, that is, return a position >= 0 of where a character occurs, or -1 if not found. In a language like C, with its pointers and low-level approach to programming, it's often just as efficient or more so to code a loop for finding a character directly, instead of using a library function like strchr(). Especially with short strings, avoiding the function call overhead is often worth a lot. Is this true of Java? Suppose that we code up a similar example: public class index { public static void main(String args[]) { String s = "aaaaaaaaaa"; int i = 250000; int n = 0; // method #1 if (args[0].compareTo("index") == 0) { while (i-- > 0) n = s.indexOf('x'); } // method #2 else { while (i-- > 0) { int len = s.length(); n = -1; for (int j = 0; j < len; j++) { if (s.charAt(j) == 'x') { n = j; break; } } } } } } When we run this code with JDK 1.0, we find that method #1 is about 3X as fast as method #2, which is the equivalent of using pointers in C. Why is this? There are a couple of reasons. One is that charAt() is a method call, and not merely a quick peek that retrieves a character at a given position. The other reason for the slower performance is that charAt() checks the index to ensure that it's within bounds. So, even though we're iterating over the characters of a String in a safe way (0 to s.length()-1), the checks are done anyway. Because of the method call overhead and the index checking, indexOf() wins easily. It avoids the method call overhead, and the index checking is not done but instead characters are accessed directly from the internal char[] vector that underlies a String. It's probably a little early to say how an area like this one will shake out. charAt() could conceivably be expanded as an inline, though it's not declared as a final method in JDK 1.0. And the subscript checking is likely to be left in place, because it's part of what Java guarantees to the programmer. 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