Java Puzzlers
Kylar writes "When you have spare time and decide to do something with a book (That's like an analog webpage, for the neuronauts among us), how often do you turn to a computer related book? How often has it happened in the last year? Right. The problem being that computer books are often either: a) boring, b) difficult to read, c) poorly written, or possibly: d) made of cheese." Read on for the rest of Kylars' review.
Traps, Pitfalls, and Corner Cases - Java Puzzlers
author
Joshua Bloch, Neal Gafter
pages
282
publisher
Addison-Wesley
rating
9 out of 10
reviewer
Tom Byrne
ISBN
0-321-33678-X
summary
95 Corner cases and traps that any serious java developer should be aware of (or entertained by.)
Java Puzzlers is none of the above(*), being well written, amusing, whimsical, and above all, informative. Bloch and Gafter have brought us a book that entertains us with corner-cases, one-in-a-million chances and other happenings that explore the ins, outs, and guts of the Java Programming Language.
Anyone who has been a serious java programmer in the last several years should know the name Josh Bloch, and more importantly, should have read his book Effective Java. Josh, acting as java's platform architect has been directing and guiding Java into it's current incarnation as a mature, robust (Cue the laughter from the peanut gallery) programming language.
This book primarily references the Java 1.5 programming language, and some of the puzzles are 1.5-specific, although a significant portion of the problems are applicable to previous versions. Also, this book is aimed towards people who are competent-to-expert java programmers, and although there is a lot of good information, people who are new to Java will probably be a bit lost. As it stands, I have 7 years of Java experience, and I was only able to figure out about 15% of the puzzles without resorting to code, or more frequently the answer. The reason that I didn't stop to try out most of these problems is that the book is eminently readable, and difficult to put down (unusual for a computer book, and doubly so for one that delves deeply into a language specification document.)
This book dives into a lot of esoteric bits of the Java Language Specification, also known as "The Big Paper That Sometimes Tells Us Why Java Acts Like That," and there are lots of bits in there that don't even make sense, let alone seem intuitive.
Divided into 10 parts, each part presents a series of different code problems that usually present a small method or class that looks innocuous, but in reality exposes a piece of behavior that is strange, spectacular, or, more often, completely confusing. The book exposes flaws in the language, including one of my personal pet peeves, their inability to have a consistent Date object, and this is noted in Puzzle 62 by my favorite line in the book: "The lesson for API designers is: If you can't get it right the first time, at least get it right the second..."
One topic that I found was a continually recurring theme had to do with handling primitives and what happens when they are cast into different types. Java provides a lot of ways to deal with primitives, and for the most part, they play nicely with each other. There are several occurrences that really surprised me. A perfect example is the following innocent statements:
byte b = -1;
char c = (char)b;
so c=-1, right? Wrong. Places like this are things that you could potentially knock your head against the wall trying to figure out why something doesn't do what it appears to do.
(In this case, byte is signed, char isn't, and the widening cast fills in bits, leaving c=65535.)
A good job is also done describing best-practices for API and library designers, as well as us, the more mundane programmers.
The only downside (from my background and point of view - that of an applications architect, and not generally as a language or API designer) - is that some of the amazing optical illustrations can cause dizziness and nausea - although I can't guarantee that won't happen by the loops and twists that your mind will be tied into because of the puzzles.
Lastly, Bloch & Gafter include an appendix that serves as a summary to all the pitfalls and traps that are introduced in the book, and almost could be an appendix to Bloch's 'Effective Java'.
The bottom line is that in reading this book I learned a fair amount about several edge cases and issues that I had actually encountered - and it increased my understanding as to HOW java does things - although I'm fairly certain that I'll never understand the WHY. And most of all - I enjoyed this book, from start to finish, and that's rare, and worth the time.
You can purchase Java Puzzlers from bn.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.
Java Puzzlers is none of the above(*), being well written, amusing, whimsical, and above all, informative. Bloch and Gafter have brought us a book that entertains us with corner-cases, one-in-a-million chances and other happenings that explore the ins, outs, and guts of the Java Programming Language.
Anyone who has been a serious java programmer in the last several years should know the name Josh Bloch, and more importantly, should have read his book Effective Java. Josh, acting as java's platform architect has been directing and guiding Java into it's current incarnation as a mature, robust (Cue the laughter from the peanut gallery) programming language.
This book primarily references the Java 1.5 programming language, and some of the puzzles are 1.5-specific, although a significant portion of the problems are applicable to previous versions. Also, this book is aimed towards people who are competent-to-expert java programmers, and although there is a lot of good information, people who are new to Java will probably be a bit lost. As it stands, I have 7 years of Java experience, and I was only able to figure out about 15% of the puzzles without resorting to code, or more frequently the answer. The reason that I didn't stop to try out most of these problems is that the book is eminently readable, and difficult to put down (unusual for a computer book, and doubly so for one that delves deeply into a language specification document.)
This book dives into a lot of esoteric bits of the Java Language Specification, also known as "The Big Paper That Sometimes Tells Us Why Java Acts Like That," and there are lots of bits in there that don't even make sense, let alone seem intuitive.
Divided into 10 parts, each part presents a series of different code problems that usually present a small method or class that looks innocuous, but in reality exposes a piece of behavior that is strange, spectacular, or, more often, completely confusing. The book exposes flaws in the language, including one of my personal pet peeves, their inability to have a consistent Date object, and this is noted in Puzzle 62 by my favorite line in the book: "The lesson for API designers is: If you can't get it right the first time, at least get it right the second..."
One topic that I found was a continually recurring theme had to do with handling primitives and what happens when they are cast into different types. Java provides a lot of ways to deal with primitives, and for the most part, they play nicely with each other. There are several occurrences that really surprised me. A perfect example is the following innocent statements:
byte b = -1;
char c = (char)b;
so c=-1, right? Wrong. Places like this are things that you could potentially knock your head against the wall trying to figure out why something doesn't do what it appears to do.
(In this case, byte is signed, char isn't, and the widening cast fills in bits, leaving c=65535.)
A good job is also done describing best-practices for API and library designers, as well as us, the more mundane programmers.
The only downside (from my background and point of view - that of an applications architect, and not generally as a language or API designer) - is that some of the amazing optical illustrations can cause dizziness and nausea - although I can't guarantee that won't happen by the loops and twists that your mind will be tied into because of the puzzles.
Lastly, Bloch & Gafter include an appendix that serves as a summary to all the pitfalls and traps that are introduced in the book, and almost could be an appendix to Bloch's 'Effective Java'.
The bottom line is that in reading this book I learned a fair amount about several edge cases and issues that I had actually encountered - and it increased my understanding as to HOW java does things - although I'm fairly certain that I'll never understand the WHY. And most of all - I enjoyed this book, from start to finish, and that's rare, and worth the time.
You can purchase Java Puzzlers from bn.com. Slashdot welcomes readers' book reviews -- to see your own review here, read the book review guidelines, then visit the submission page.
I'm somewhat puzzled by the premise of the book. I thought C/C++ was full of puzzlers, and that Java was supposed to fix all that. Puzzlers may be cute, but they are definitely bad (except for job security may be). BTW, my little test shows that this example also applies to C, except that it isn't as surprising since you have to specifically declare the variable as unsigned, e.g.
int b = -1;
unsigned char c = (unsigned char)b;
Without "unsigned", char is -1, as expected.
I'm curious as to why this user's post was marked "informative". There are many places to buy the book, and the story provided one. In fact, the only significant difference between this link and the story is that this person has apparently posted a referral link to make some money.
What's the difference between short and char in Java?
One is signed, the other is unsigned.
chars are treated just like numbers in Java. You can do numeric comparisons with them, you can add them, you can subtract them, they're just numbers.
By definition, a char in Java is a 16-bit unsigned value. It happens to represent a single UTF-16 sequence, although arguably you could have done that using a short.
But, here, check the language spec. A char is just an unsigned short. That's it.
You are in a maze of twisty little relative jumps, all alike.
Well, maybe that's the intended purpose. But its semantics don't sit totally easy with that. What does this print? (from p.25)
System.out.println('H' + 'a');
It prints '169'. The book goes on:
From a linguistic standpoint, the resemblance between char values and strings is illusory. As far as the language is concerned, a char is an unsigned 16-bit primitive integer - nothing more.
Yeah, in practice this sort of thing is mainly irrelevant, because you wouldn't actually USE chars like that. Still, it's interesting stuff.
fud, notfud, yes, no, maybe
Can't be helped. You have to give the computer a way of understanding characters. Array indexes are a natural way for computers to do that.
That's not to say the idea of a character coding that translates between characters and numbers isn't sensible, but the character itself is not a number - it's a character.
A character in Java *is* a character. Nothing more, nothing less. It's a character. What the author did was stupid. The only time you cast a character like that is when you're doing I/O. For example:Note that in.read() returns an Integer of byte data, so the sign problem never shows up.
I like Python's approach to the solution - there simply is no "atomic" character type (defining such a thing when character sets have characters that aren't uniform size is questionable anyway)
Java Characters *are* a uniform size. Every character is a 16 bit Unicode character. That's why you're not supposed to do what I just did in the example above (read in a byte at a time) because you may chop up the Unicode encoding. Instead you're supposed to use a Reader object, which will return 'char' values instead of 'int' values.
Javascript + Nintendo DSi = DSiCade
When the Java syntax was being invented (borrowed from C is more like it), this should have been addressed by disallowing return statements within finally blocks. The only way control should exit a finally clause is by falling out the end.
Or even worse, the lack of an unsigned byte when reading in binary data structures. I don't claim to be a Java expert by any stretch (so I may be missing an obvious way to do this), but do you know how unnecessarily complex it is to convert a read-in byte to it's CORRECT unsigned value? Why isn't there an automatic way to do this at all? You can't just assign the byte to an int, as it'll still be negative (if above 127). I think in the end I just asigned the byte to an int, then did a bitwise-AND to throw out the extra sign bits it tacked on in the widening conversion so that it was back to positive.
InputStream.read() doesn't return a byte. It returns an int between 0 and 255 inclusive. -1 means EOF. The most common idiom is to do something like this:
int i;
int numRead = 0;
while ((i=inputStream.read()) >= 0)
someByteArray[numRead++] = (byte)i;
For bytes with values between 128 and 255 inclusive, the values will become negative. And why do you care? As long as every single one of the eight bits in each byte is correct, signed vs. unsigned is in the eye of the beholder. It doesn't enter into anything unless you start doing arithmetic on the bytes or print their numeric values, both of which involve implicit casts to int. To do arithmetic, Java always converts a byte, char, or short to int using an automatic, implicit cast (it converts float to double as well). If the bytes have unsigned semantics in your program, then never allow the compiler to implement an implicit cast since implicit casts assume signed values. Replace them with explicit casts that mask out the top 24 bits to zero yourself, preserving the semantics with respect to sign:
int intVal = (0xFF & byteVal)
When evaluating this expression, byteVal will be implicitly cast to a signed int and then the & operator zeroes out the sign extension bits to preserve semantics. Is this "unnecessarily complex"? I don't think so. I rarely even need to do it.
This seems to horrify people used to the unsigned-type train wreck in ANSI C but I would not welcome unsigned types being added to Java at all. The existing type system in Java is perfectly adequate for getting work done and you don't have to keep remembering whether variables were declared as signed or not if you know they're always signed.
Since there is a String class that exists within the bad class, this prototype:
public static void main(String[] args)
is the same as this:
public static void main(bad.String[] args)
and java can't find any main to execute because it is looking for:
public static void main(java.lang.String[] args)
See?