Java Examples in a Nutshell by David Flanagan Unconfirmed error reports are from readers. They have not yet been approved or disproved by the author or editor and represent solely the opinion of the reader. This page was updated October 15, 2003. Here's a key to the markup: [page-number]: serious technical mistake {page-number}: minor technical mistake : important language/formatting problem (page-number): language change or minor formatting problem ?page-number?: reader question or request for clarification UNCONFIRMED errors and suggestions from readers: {27} first line in the main() in the static class Randomizer.Test: The line in context is Randomizer r = new Randomizer((int) new java.util.Date().getTime()); The casting to int of the long data can change a positive long number to a negative integer. [30] method removeFromHead, Example 2-8 LinkedList: The statement node.setNext(null); is unnecessary, I think, since the current head node is being dereferenced and is therefore subject to garbage collection, so whether it references the next node is a moot question. In the remove method on the next page the reference to the next node is not nulled out whether the node being removed is a head node or not. {33} In the advanced sorting example, the return values in Comparable should be 1, 0 and -1. [43] code for Sorter.java; If I try to compile the Sorter.java Code there's some errors, concerning the class ComplexNumber (cannot resolve sysmbol) The same happens to the method magnitude ... My problem is that this happens with my own written text AND the downloaded code from this site. Is this a problem with my own java installation or an error in the program code? ?39? This is not a mistake, exactly, but it would be nice if you mentioned in the section on applets that: 1) Netscape and IE cache your applet 2) Requesting that the browser clear the cache does not clear the "java cache" 3) The "java cache" can be cleared by holding down the "shift" key (in Netscape) or "control" key (in IE) while clicking on the "reload" button. {48} Example 3-5, Soundmap.java: This example will not compile with JDK 1.2.2 - get the following 5 compile errors when trying to compile the example file downloaded from your site: D:\Data\Ian\Java\Examples\Applets>javac Soundmap2.java Soundmap2.java:94: Undefined variable: Applet.this Graphics g = Applet.this.getGraphics(); ^ Soundmap2.java:97: Undefined variable: Applet.this Applet.this.showStatus("To: " + r.url); // display URL ^ Soundmap2.java:107: Undefined variable: Applet.this Graphics g = Applet.this.getGraphics(); ^ Soundmap2.java:110: Undefined variable: Applet.this Applet.this.showStatus(""); // Clear the message. ^ Soundmap2.java:113: Undefined variable: Applet.this Applet.this.getAppletContext().showDocument(r.url); // Go to the URL ^ Seems to compile OK if all instances of "Applet.this" are changed to "Soundmap.this". {49} Java statement on line 29 and following lines -- in 4 other statements...: Change "Applet.this" to "Soundmap.this." The syntax for this changed with Java 2. Applet.this worked fine with 1.1, but won't work under 1.2. (63) 2nd comment on code of Example 4-5: "A timer for animation: call our animate() method ever 100 milliseconds" should read "A timer for animation: call our animate() method every 100 milliseconds." {75} bottom: When the PrintScribble application prints on a Mac, the scribbled lines and the clip rectangle are translated another [100, 100] beyond the [100, 100] translation of the border. The Print button prints in the expected location (though it would be outside the translated clip). If the "g.translate(100, 100);" line is commented out, everything aligns normally, though "scrunched up in the upper-left corner of the page." This may be a Mac-specific bug rather than an error in the program. {118} 1st paragraph: For reshape(), Java 1.0 should be Java 1.1. [124] MenuScribble.java example: The popup menu for the applet version of this program does not "pop-up" in the latest releases of Netscape (v 4.74) and Internet Explorer (v 5.5) browsers. It does work in the AppletViewer. {126} lines 10 and 15 of code: neither function definition: this.addMouseListener() and this.addMousrMotionListener() compiles, resulting, instead in a Type expected exception. {142-144} Example 7-1, Simple String Cut-and-Paste: Compiled with jdk1.1.7, the program does NOT write anything to the clipboard -- this can be verified either with the clipboard viewer supplied with Windows or by printing out the value returned by the getContents() method in the paste() function. [176] listed program: The program does not work correctly. When run on a Windows 98 PC using Java 1.3, HardcopyWriter$Demo and HardcopyWriter$PrintFile only print out the line at the top of the page. The code was downloaded from your website. The printer used is a Hewlett Packard Deskjet 600. [188] Example 9-3, Sendmail.java: Sending email through a URL connection: same sort of problems with println() as mentioned in errata for [161] (in the "confirmed errors" above). But the Sun JDK 1.1.6 support for "mailto" seems seriously broken on an NT machine. The example invisibly sends helo machinename mail from: username@machinename data which fails for many SMTP servers which don't allow data until an RCPT from: has been given too. I got to the bottom of this using a heavily edited SendMail example, the GenericClient example and by modifying the HttpMirror example to mimic an SMTP server, and by playing with a telnet session to a real ESMTP server (SendMail 8.8.8/8.8.8) running on a Sun. Editor's note: This sounds like a bug in the JDK, not in the code in the book. if (searchType == (SEARCHANY | SEARCHALL)) { requireAll(searchArray); } MUST BE if (searchType == (SEARCHALL)) { requireAll(searchArray); } var refineAllString = allString.substring(0,allString.indexOf('|HTTP')); MUST BE var refineAllString = allString.substring(1,allString.indexOf('|HTTP')); In the book is the example of records.js incorrect. It starts with the url. The source ends with the url. {191} Example 9-4: // (corrected in 9781565923713.1298) to_server.println("GET " + filename + "\n"); should be to_server.print("GET " + filename + "\r\n"); Internet RFC indicates that new line is CR-LF. But this example depends on platform. Particularly on Macintosh, this code is incorrect. But on most UNIX servers, this may work. Refer to http://devworld.apple.com/technotes/tn/tn1157.html. {202} Example 9-9, Server.java: I just noticed a problem with the example server.java... The problem is with the println() function called.... he is assuming that it is going to print out \r\n at the end of every line, which is what is needed for most tcp-ip protocols... but on the mac and unix, this isn't what happens. On the mac, \r is sent out at the end of println, and on unix, \n is sent out. The problems work on unix, even though the protocol is incorrect, but it doesn't work correctly when the server is run on a mac. The println()'s should be replaced with print("\r\n") where needed, which is just about everywhere. Notice that this isn't a problem with the mac, or windows, or unix, it's part of the java specifications. So in short, don't use println() when using tcp/ip communications, use println("\r\n"). (Supposedly, this worked fine in java 1.0.2, but javasoft changed this for 1.1) Editor's note: This is a valid point and will be fixed in the next edition. [205] whole page: I use Java 2 on Windows 2000 and Java 1.1.6 on SunOS 5.6. You can't remove a service properly. The ServerSocket "listen_socket" remains on the port ad infinitum. There seem to be two errors: a) half-way down the page in the Listener constructor, the author passes a dummy value to setSoTimeout (10 minutes) to allow an interrupt() call to interrupt the accept() call in the Listener.run() method at the bottom of the page. I don't think that anything will allow an interrupt() call to affect a blocking IO call like accept(). This means Listeners never return from Listener.run(). The solution is to use setSoTimeout for real, passing it a low value like 1 second (1000). This causes a lot of polling, and may cause performance problems. You might as well remove the otiose line "this.interrupt();" in the Listener.pleaseStop() method as well. All of this is due to the Java thread model not handling IO very well. b) Even when Listeners die in a timely fashion, the ServerSocket still survives. I even tried an explicit call to System.gc(), which had no effect: it seems that you need to close the Sockets directly, the garbage collector won't do it for you when the last reference goes out of scope. Here is the fixed Listener code: public class Listener extends Thread { ServerSocket listen_socket; // The socket we listen for connections on int port; // The port we're listening on Service service; // The service to provide on that port boolean stop = false; // Whether we've been asked to stop /** * The Listener constructor creates a thread for itself in the specified * threadgroup. It creates a ServerSocket to listen for connections * on the specified port. It arranges for the ServerSocket to be * interruptible, so that services can be removed from the server. */ public Listener(ThreadGroup group, int port, Service service) throws IOException { super(group, "Listener:" + port); listen_socket = new ServerSocket(port); // give the socket a non-zero timeout so accept() can be interrupted /** @todo: set this timeout value to something reasonable for your system. */ listen_socket.setSoTimeout(6000); this.port = port; this.service = service; } /** This is the nice way to get a Listener to stop accepting connections */ public void pleaseStop() { this.stop = true; // set the stop flag } /** * A Listener is a Thread, and this is its body. * Wait for connection requests, accept them, and pass the socket on * to the ConnectionManager object of this server. */ public void run() { while(!stop) { // loop until we're asked to stop. try { Socket client = listen_socket.accept(); connectionManager.addConnection(client, service); } catch (InterruptedIOException e) {} catch (IOException e) {log(e);} } /** @todo: do we really need to close this socket explicitly? */ try { listen_socket.close(); } catch (IOException e) { log(e); System.err.println("Service removed, but couldn't close server socket."); } } } {205} public void run(): I'm running the Generic Multi-Threaded Server of example 9-9 on my Linux workstation. After removing a service on a port with the -control option, it's still possible to connect to this port with the Generic Client of example 9-8. (There's no reaction of the service.) To avoid this, I would explicitly close the listen_socket at the end of the run()-method: try { [207] The body of the ConnectionManager.run() method in the example; The code sample below the comment "Check through the list of connections, removing dead ones" traverses the "connections" vector in the forward direction, removing "dead" connections from the vector as it goes: for(int i = 0; i < connections.size(); i++) This does not work properly, as the size of the vector and the indices of the elements are changed in the body of the loop. This should be changed to: for(int i = connections.size() - 1; i >= 0; i--) Also note that the "Connection" threads don't seem to cooperate well (try doing something non-trivial in a service), at least with my configuration - Windows 2000 Pro, JDK 1.4.2 - even with the addition of calls to Thread.yield() sprinkled liberally throughout. I have been able to solve this by setting the connection threads to low priority. (226) Pipes.java: It is not very clear where "elsewhere" is for GrepReader class. It is of course in Chapter 8, "Input Output.Filtering Lines Of Text()," p. 171. To compile, the program needs to have this class (nope...) Uh, sorry - Source file (.java) not class.