Hardcore Java by Robert Simmons This errata page lists errors outstanding in the most recent printing. If you have technical questions or error reports, you can send them to booktech@oreilly.com. Please specify the printing date of your copy. This page was updated July 14, 2004. 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 Confirmed errors: (Back Cover) End of second paragraph; "error-prone" should be changed to "error-proof" (xiv): "I take my hat of to" should read "I take my hat off to" (xv): "Copyright 2001 O'Reilly" should read "Copyright 2004 O'Reilly" (xvi) Replace Paragraph I would like to take a moment to say ŇHiÓ to my brother Paul and my sister Debbie. I currently live in Germany, and although I am very happy living here, I miss my brother and sister greatly. with I would also like to thank my new wife Alma for being the wonderful person she is and supporting me through all of my efforts to write and maintain this book. In addition, I would like to thank all of my readers from all over the world who have submitted errata. Your vigilance has helped refine my work and kept me honest. I look forward to your feedback, concerns and questions. (4) First bullet point at the top of the page. Second sentence.; "This means that all the objects that are be stored in collection classes ultimately have to descend from one class." Should be: "This means that the classes of all the objects that are to be stored in collections must descend from one class." (4): "Example 1-4 shows the getclass() method in action" should read "Example 1-4 shows the getClass() method in action" (5): "b = (A) a1; // compiler error: a1 is not a B" should read "b = (B) a1; // compiler error: a1 is not a B" Same in the compilation trace a little further on the same page (5) Middle of the compilation output [javac] b = (A)a1; // compiler error: a1 is not a B. should read [javac] b = (B)a1; // compiler error: a1 is not a B. (6) Last paragraph because the evaluation of the if statement is abbreviated at runtime. Should read because the evaluation of the condition within the if statement is abbreviated at runtime. (7) After the end of the first paragraph, add the following inset note: The abbreviation of the evaluation in this if statement isnŐt unique to the if statement. In fact it is actually a property of the && operator itself. Many other conditional evaluation operators such as || will short circuit in evaluation as well. Once the evaluation reaches a point where subsequent evaluations cant change the value of the evaluation, the computer stops processing the evaluation. (Note that the operators && and || in constant width font. ) (7) Second to last paragraph Ternary statements Should be Ternary expressions {9} Second code snippet: Point element = null; Iterator iter = points.iterator( ); for (int idx = 0; iter.hasNext( ); idx++) { should read Point element = null; int idx = 0; Iterator iter = points.iterator( ); for (int idx = 0; iter.hasNext( ); idx++) { (9) Last paragraph The allocation statement in the for loop is executed when the loop is set up. At each iteration of the loop, the expression in the middle is evaluated and, if the expression is true, the iteration statement is run. Should read The allocation statement in the for loop is executed when the loop is set up. At each iteration of the loop, the expression in the middle is evaluated. Each time the expression is evaluated as being true, with the exception of the first time, the iteration statement is run. (12): "Finally, if she inputs anything else, the result will be Option 4" should read "Finally, if the user inputs anything else, the result will be Option 3"> (12) last paragraph; Without the break, you would always get "Option 4" Should be Without the break, you would always get "Option 3" (12 + 13) code samples showing break usage; There are one too many closing braces in all three of the code samples in this section (decode, decode, and matrixMeth). (12) last paragraph; Should be "Option 3" instead of "Option 4" in "Finally, if she inputs anything else, the result will be "Option 4"." Same thing in "Without the break, you would always get "Option 4" as the result of the method..." (14) First paragraph However, the break statement doesnŐt do this. It merely breaks out of its current loop. Should read: However, the break statement doesnŐt do this. It merely breaks out of the block in which it is contained, which in this case happens to be the innermost loop. {14} First Code Snippet (only code snippet) Replace entire snippet with the following code. package oreilly.hcj.review; public class SyntaxIssues { public static void continueFunc() { int complex = 0; int processing = 0; for (int idx = 0; idx < 1000; idx++) { // ... do some complex code. complex++; if (idx == 555) { break; } // ... processing code processing++; } System.out.println(" Complex: " + complex); System.out.println("Processing: " + processing); System.out.println("------------------------------"); complex = 0; processing = 0; for (int idx = 0; idx < 1000; idx++) { // ... do some complex code. complex++; if (idx == 555) { continue; } // ... processing code processing++; } System.out.println(" Complex: " + complex); System.out.println("Processing: " + processing); } } {14} Second to last paragraph In the first loop, the processing code is executed only 554 times. it should say: In the first loop, the complex code is executed 556 times whereas the processing code is executed only 555 times. {14} Second to last paragraph However, in the second loop the processing code is executed 999 times. Should say However, in the second loop the complex code is executed 1000 times while the processing code is executed only 999 times. (15) Paragraph right before the last code sample. Replace the paragraph Once you have declared the label, you can use it in a break or a continue statement. The following code shows how you can use break to repair a faulty matrix: With the following text Once you have declared the label, you can use it in a break or a continue statement to exert more control over how they work. The following code demonstrates how you can use break to exit out of deeply nested loops: (15) Note on the page Change the word semantics To Scope (15) Last code snippet: Replace all occurrences of RESTART With PROCESS_LOOP [15 -16] Final paragraph (starts on 16 and ends on 17) Replace the paragraph In this version, if an error condition is detected, the method will try to repair the error condition and then start to process the matrix all over again. This is accomplished by the break RESTART; statement. This statement tells the virtual machine to immediately transfer control to the statement labeled RESTART. This will work only if the break statement is nested inside the labeled statement. Otherwise, the compiler will just laugh at you sardonically and tell you that the label RESTART isnŐt declared. With the following text In this method, if any of the Points in the matrix contain a negative number for the x or y attribute, the break statement will cause the virtual machine to exit the block labeled by the PROCESS_LOOP label. This will work only if the break statement is nested inside the labeled statement. Otherwise, the compiler will tell you that the label PROCESS_LOOP isnŐt declared. {16} First code snippet Replace entire code snippet with the following code. package oreilly.hcj.review; public class SyntaxIssues { public static void matrixMeth3(final Point[][] values) { int ctr = 0; LINE: for (int x = 0; x < values[0].length; x++) { COLUMN: for (int y = 0; y < values.length; y++) { LOGLINE: System.out.println(values[x][y].toString()); if ((values[x][y].x < 0) || (values[x][y].y < 0)) { continue LINE; // skip the rest of the line; } // do something with the value ctr++; } } System.out.println("Elements processed: " + ctr); // continue processing PASS_TWO: for (int x = 0; x < values[0].length; x++) { // do some code. } } } (17) 2nd paragraph; Should be "Boolean_Expression" instead of "Expression" in "In this form, Expression is replaced by an expression that evaluates to a boolean result." {18} 1st paragraph; Should be "since the declaration is not an expression" rather than "since the evaluation of the expression is void" in "An attempt to do something like this would be rejected by the compiler since the evaluation of the expression is void." The evaluation of the expression s = "args cannot be null." is not void, so it is not the "evaluation of the expression" that is the problem. The problem is the fact that String s = "args cannot be null." is not an expression. {19} 2nd code sample; The first two lines should be deleted: package oreilly.hcj.review; public class Assertions { Instead, the code should start with the 2nd "package" line. (20) 2nd paragraph (with the "note" icon); Should be "It's" instead of "Its" in "Its better to use assertions so that programs can at least limp along..." (20): In the third bullet, "... that it will never to return null to the user" should read "... that it will never return null to the user" (23) 1st paragraph; Should be "lose" instead of "loose" in "Although you will loose some performance and incur a few crashes..." (29): static{} is not a so-called method Moreover, you should make it clear that a static initializer is not only useful for assigning constants, aka static final fields, but also conventional static fields. (34): On the fourth line, "handleOKbtn()" should read "handleOKBtn()" {39}: Mispaced patentheses in catch clause and missign parameter: public void someMethod() { try { // do a whole bunch of stuff } (catch IllegalAccessException ex) { throw new MyApplicationException(); } } should be public void someMethod() { try { // do a whole bunch of stuff } catch (IllegalAccessException ex) { throw new MyApplicationException(ex); } } (46) 1st paragraph, which immediatly follows the code sample which starts the page; Therefore, the following two lines are identical from the point of view of the compiler: public final static String A_STRING = "Hardcore Java"; public final static String A_STRING = "Hardcore"+ "Java"; The second line is missing a space, and should be: public final static String A_STRING = "Hardcore "+ "Java"; [53] Section Chaining Finals; This section should have been yanked out of the book before production but slipped through the proverbial cracks. The fact is that the example: package oreilly.hcj.finalstory; public class ChainingFinals { public final String name; public final int nameLength = this.name.length(); // public final String anotherValue = name; // <== Won't compile public ChainingFinals(final String name) { this.name = name; } } Will compile but you cannot create an instance of the variable because the initializers are run before the body of the constructor an thus you will get a null pointer exception. Unfortunately I forgot to pull the section and no technical reviewers caught it. (53) in the code blocks public final int nameLength = this.name.length; Should be: public final int nameLength = this.name.length(); public final int nameLength = name.length; should be: public final int nameLength = name.length(); (54): In example 2-9, it would be wise to mention that the final modifier does not protect the parameter (which is passed by value), but it protects its use in the computation of the method. {56}: "nonimmutable" should be "non-immutable" or merely "mutable" (58) End of Paragraph 2; The word "UnmodifableCollection" should read "UnmodifiableCollection" {59} last paragraph; the text - When you call Collections.unmodifiableSet(), the class creates a new instance of this static nested class and sets the source collection as the delegate object. As you can see in the example code from the JDK, the class UnmodifiableSet implements java.util.Set and inherits from UnmodifiableCollection, which in turn implements java.util.Collection. Should be changed to - When you call Collections.unmodifiableSet(), the class creates a new instance of the static nested class UnmodifiableSet and sets the source collection as the delegate object. The class UnmodifiableSet, which is similar to the UnmodifiableCollection class shown in the example, implements java.util.Set and inherits from UnmodifiableCollection, which in turn implements java.util.Collection. {60} First paragraph; The Text: ------ This delegate structure also plugs another big hole: if the UnmodifiableSet class inherited from HashSet, then the user could just cast the instances back to HashSet to gain access to write methods. The delegate structure in the JDK quite elegantly blocks this, ensuring that an UnmodifiableSet truly is unmodifiable, even when placed in the hands of a clever and sneaky programmer. ----- Should be removed. You cant cast something to something it isnt. In this case casting it up would not result in the methods of the superclass beign called since all methods in java are virtual. {75}: Use IllegalArgumentException instead of NullPointerException (see class comment for NullPointerException) {91}: The caption for Example 4-1 should be "A Tax Id comparator" [102] 2nd paragraph; heading java.util.LinkedSet should be java.util.LinkedHashSet (103): On figure 4-5, "<> Key/Value Storage" should be added as a label of the relationship between the Use Map and the Collection Decision use cases. (105): "...and these reverences..." should read "...and these references..." (108): "If this technique adopted as a..." should read "If this technique is adopted as a..." {117}: In the first code example, "reflectionMethod3" should be "reflectionMethod4" (117): In the paragraph before Example 5-3, "RuntimExceptions" should read "RuntimeExceptions" (122): "In the try-catch-finally triad, is the finally clause is often..." should read "In the try-catch-finally triad, the finally clause is often..." (123) Last but one paragraph; Change "The catch clause is this example .." to "The catch clause in this example .." [125] Code snippet; The lines: for (idx = 0; idx < columnCount; idx++) { record[idx] = rs.getObject(idx); } should read: for (idx = 0; idx < columnCount;) { record[idx] = rs.getObject(++idx); } {126} Code snippet; The lines: for (idx = 0; idx < columnCount; idx++) { record[idx] = rs.getObject(idx); should read: for (idx = 0; idx < columnCount;) { record[idx] = rs.getObject(idx + 1); [127] Code snippet; The lines: for (idx = 0; idx < columnCount; idx++) { record[idx] = rs.getObject(idx); } should read: for (idx = 0; idx < columnCount;) { record[idx] = rs.getObject(++idx); } (131) first paragraph, fourth sentence; "Not all types of nested classes should be used routinely, so you will likely encounter most of them in other people's code" should be "Not all types of nested classes should be used routinely, but you will likely encounter most of them in other people's code" (135) 2nd paragraph; Also, make sure that an abstract inner class ... should rather be Note that an abstract ... The developer must not verify anything. [136] 2nd codesample; System.out.println(resoultion); should be System.out.println(resolution); (147): "...see the source code to java.util.HashTable" should read "...see the source code to java.util.Hashtable" (151) Table 6-1; Heading "Keywords" in the title of the table should start from abstract/final, not instance. {164}: Invert the two code blocks where the LOCALE constants are initialized, i.e. String should be int and vice versa (166) Last paragraph; "Suupose you introduce the country of Uruguay and give it the value of 1 by accident." should be "Suppose you introduce the country of Uruguay and give it the value of 6 by accident." {168} Example 7-8; public final class NetAppException2 extends Exception { Should be public final class NetAppException2 extends ConstantObject { (169): In Example 7-9, the content of the comments is not synchronize with purpose of the class. (178): In the first code example, the package declaration ("package.utiulities;"), is not well-formed. (190): On the first line, "commonalties" should read "commonalities" (192): "...the data model is fairy substantive" should read "...the data model is fairly substantive" {197}: In the last code example, the firePropertyChange doesn't take the oldInterestRate as parameter. (Two occurences) (212): "...and blue values are between 0 and 256" should read "...and blue values are between 0 and 255" (213): "Consider the UML diagram in Figure 8-6..." should read "Consider the entity-relationship diagram in Figure 8-6..." {221}: "The getMethods() call extracted each of the public members of the Person class" should read "The getMethods() call extracted each of the public method members of the Person class" since getMethods() does not extract field members {226}: The JavaBeans conventions mention that the method to set/get a single property, should be named setValue() and not setValues() getValue() and not getValues() (262): Show the arrows going to and from data object as two different arrows. (266): "...or causes the class holding the reference variable to go out of scope" should read "...or causes the object holding the reference variable to go out of scope" since a class does not hold a reference. {278-279-289-290-291}: The package declaration "package oreilly.hcj.tiger." is not well-formed. (281): The method name "setMehtod" should read "setMethod" (291): "Substitution continues until the all of the arguments are used" should read "Substitution continues until all the arguments are used" {297}: new Pair() should be new Pair() because the left type is a String ("John") and the right type is an Integer (25) {308}: The "Third" someMethod is declared twice.