CODE TALK with Josh Bloch and Neal Gafter - Part II
Neal: Welcome to this week's edition of Code Talk. In spite of last week's fiasco, they've given us a chance to redeem ourselves with another column. We left you with two puzzlers to solve. Each puzzler consisted of a loop that looked like it did nothing, and you were supposed to come up with a declaration for the variable i that caused the loop to spin forever. Here's the first loop:
while (i != i + 0) ;
Josh: Couldn't we just set i equal to Double.NaN like we did last week?
Neal: No you dummy, you were supposed to solve these puzzlers without using any floating point.
Josh: Oh, well, how about this:
String i = "Buy seventeen copies of Effective Java!";
Neal: Oooh, clever... That turns the plus sign into the string concatenation operator. Then the int 0 is converted to the string "0" and appended to the blatant plug.
Josh: Yep. The plus sign is overloaded, and operator overloading can be very misleading. It looks like addition, but it's really string concatenation.
Neal: It's even more misleading because I called the variable i. Good variable, method and class names are as important to the documentation of a program as good comments. Now on to the second problem. As you'll recall the loop was:
while (i != 0) i >>>= 1;
Josh: I have no idea how to solve that one! For the shift to be legal, i has to be an integral type, and the unsigned right shift operator will produce a result closer to zero on each iteration.
Neal: That's almost right, but there's one small twist that throws a wrench in to your logic. The >>>= operator is an assignment operator, and assignment operators have a hidden cast in them. The cast can be a narrowing cast, which throws away information.
Neal: OK, suppose you use this declaration:
short i = -1;
Here's what happens. First the value of i (0xFFFF) is promoted to an int; all arithmetic operations do that if their operands are of type short, byte, or char. The promotion involves sign extension, so the resulting value is 0xFFFFFFFF. This value is shifted right one bit without sign extension, which yields 0x7FFFFFFF. Now here's the kicker: when this value is stored back into i, the implicit narrowing cast that I mentioned earlier chops off the high order 16 bits, leaving 0xFFFF, and we're back where we started.
Josh: Ouch! So assignment operators are pretty dangerous when you use them on short, byte and char values?
Neal: Yep. You end up doing mixed mode arithmetic, which is always a tricky business. Worse, you end up doing a narrowing cast even though it doesn't show up in the code.
Josh: Great. Well, I guess it's time for me to give out this week's puzzlers:
Write a method that takes a Vector of elements and returns a new Vector containing the same elements in the same order, with the second and subsequent occurrence of any duplicate elements removed. For example, if you pass in a Vector containing "Spam", "Spam", "sausage", "eggs", "Spam", "Spam", and "Spam", you'll get back a new Vector containing "Spam", "sausage", and "eggs".
Write a method that takes a string containing zero or more tokens separated by commas, and returns an array of strings representing the tokens in the order they occur in the input string. Each comma may be followed by zero or more whitespace characters, which are ignored. For example, if you pass in the string "butter, eggs,milk, whirled peas", you'll get back a four element string array containing "butter", "eggs", "milk" and "whirled peas".
Write a method that takes a sorted array of ints and a "target" int, and returns true if the array contains the target, false if it doesn't.
Write a program that prints a line telling you how many times it has been run. The first time you run it, it should print "This is run number 0"; the second time it should print "This is run number 1", and so forth.
Neal: Wait a minute, are you telling me that the program has to remember stuff from run to run?
Josh: Yep. See you next week, and till then, don't code like my brother.
Neal: Don't code like my brother.