x < y | Less than | True if x is less than y, otherwise false. |
x > y | Greater than | True if x is greater than y, otherwise false. |
x <= y | Less than or equal to | True if x is less than or equal to y, otherwise false. |
x >= y | Greater than or equal to | True if x is greater than or equal to y, otherwise false. |
x == y | Equal to | True if x equals y, otherwise false. |
x != y | Not equal to | True if x is not equal to y, otherwise false. |
On p. 117, both programs 5.1 and 5.2 print "The strings are the same." in Java 1.0.2 and later. The program works as advertised in Java 1.0.1 and earlier. An optimization was introduced in Java 1.0.2 where identical String literals are only stored once in the .class file. This isn't a problem for most code because strings are immutable. Regrettably Example 5.1 is one of the exceptions. Thus if you run Program 5.1 as written in the book, the output will claim the strings are the same because, in Java 1.0.2 and later, they really are the same object. There's only one string here, not two, although there are two references to it.
If you use constructors to create the strings, then the program behaves as advertised. There are now two strings with one reference to each rather than one string to which two references exist. Thus program 5.1 should now bet this:
class JackandJill {
public static void main(String args[]) {
String s1 = new String("Jack went up the hill.");
String s2 = new String("Jack went up the hill.");
if (s1 == s2) {
System.out.println("The strings are the same.");
}
else if (s1 != s2) {
System.out.println("The strings are different.");
}
}
}
Program 5.2 should look like this:
class JackandJill {
public static void main(String args[]) {
String s1 = new String("Jack went up the hill.");
String s2 = new String("Jack went up the hill.");
if (s1.equals(s2)) {
System.out.println("The strings are the same.");
}
else {
System.out.println("The strings are different.");
}
}
}
Incidentally, these revised versions work in Java 1.0 and 1.0.1 as well as Java 1.0.2 and later.
On p. 124 there should be semicolons after the while
statements, that is
do {
// what you want to do
} while (condition);
class CountToTen {
public static void main (String args[]) {
int i=1;
do {
System.out.println(i);
i = i + 1;
} while (i <= 10);
}
}
On p. 128, Program 5.10 should double the number of grains after adding them to the total rather
than before. The correct code and output is as follows:
class CountWheat {
public static void main (String args[]) {
int i, j, k;
j = 1;
k = 0;
for (i=1; i <= 64; i++) {
k += j;
j *= 2;
System.out.print(k + "\t ");
if (i%4 == 0) System.out.println();
}
System.out.println("All done!");
}
}
Here's the output:
% javac CountWheat.java % java CountWheat 1 3 7 15 31 63 127 255 511 1023 2047 4095 8191 16383 32767 65535 131071 262143 524287 1048575 2097151 4194303 8388607 16777215 33554431 67108863 134217727 268435455 536870911 1073741823 2147483647 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 All done! %On p. 129, Example 5.11 has the same problem. Here's the correct version:
class CountWheat {
public static void main (String args[]) {
int i;
double j, k;
j = 1.0;
k = 0.0;
for (i=1; i <= 64; i++) {
k += j;
System.out.print(k + "\t ");
if (i%4 == 0) System.out.println();
j *= 2.0;
}
System.out.println("All done!");
}
}
Finally, on p. 131 Example 5.12 also increments before it adds instead of adding before incrementing.
The correct version of its code and ouptut is
class CountWheat {
public static void main (String args[]) {
int i, j, k;
j = 1;
k = 0;
for (i=1; i <= 64; i++) {
k += j;
if (k <= 0) {
System.out.println("Error: Overflow");
break;
}
System.out.print(k + "\t ");
if (i%4 == 0) System.out.println();
j *= 2;
}
System.out.println("All done!");
}
}
Here's the output:
% java CountWheat 1 3 7 15 31 63 127 255 511 1023 2047 4095 8191 16383 32767 65535 131071 262143 524287 1048575 2097151 4194303 8388607 16777215 33554431 67108863 134217727 268435455 536870911 1073741823 2147483647 Error: Overflow All done!On p. 133-134 I really messed up the details of the switch statement. The labels of a case statement can only be literals or
final static int
fields. They cannot be variables or expressions as
I claim in the book. This has to do with how Java compiles a switch
statement in the virtual machine. The actual numeric values of the case
statements
are embedded in the byte code. This makes switch
statements much more
efficient than they otherwise would be.
Here's how it should read:
Java has a shorthand for these types of multipleIt is not true that multipleif
statements, theswitch-case
statement. Here's how you'd write the above using aswitch
statement:
In this fragmentswitch (x) { case 0: // do thing 0...; break; case 1: // do thing 1...; break; case 2: // do thing 2...; break; case 3: // do thing 3...; break; default: // do thing 4...; }
x
must be a variable or expression that can be cast to an int without loss of precision. This means the variable must be or the expression must return an int, byte, short or char.x
is compared with the value of each the case statements in succession. This fragment comparesx
to literals, but these too could be variables or expressions as long as the variable or result of the expression is anint
,byte
,short
orchar
.Once a
case
statement is matched all executable statements following it are executed including those in subsequent, unmatchedcase
statements. This can trigger decidedly unexpected behavior. Therefore it's common practice to include thebreak
statement at the end of eachcase
block. If thebreak
s weren't included in the above code fragment and case 1 were matched, then not only thing 1 but also thing 2, thing 3, and thing 4 would be performed. It's important to remember that theswitch
statement doesn't end when one case is matched and its action performed. The program continues to look for additional matches unless specifically told to break.Finally if no cases are matched, the default action is triggered.
case
statements are matched as I claimed in the book.
Thanks are due to Bob Follek
for catching these mistakes.
On p. 136 the last two paragraphs about the ?:
operator are completely wrong.
Replace them with the following:
The conditional operator only works for assigning a value to a variable, using a value in a method invocation, or in some other way that indicates the type of its second and third arguments. For example, consider the following
This may not be written like this:if (name.equals("Rumplestiltskin")) { System.out.println("Give back child"); } else { System.out.println("laugh"); }
First of all, both the second and third arguments are void. Secondly, no assignment is present to indicate the type that is expected for the second and third arguments (though you know void must be wrong).name.equals("Rumplestiltskin") ? System.out.println("Give back child"); :System.out.println("Give back child");;
The first argument to the conditional operator must have or return boolean type and the second and third arguments must return values compatible with the value the entire expression can be expected to return. You can never use a
void
method as an argument to the? :
operator.