Abstract: Experienced Java programmers will love the Java Puzzlers book by Josh Bloch and Neal Gafter, both well known Java personalities. In this newsletter, we look at two of the puzzles as a teazer for the book.
Welcome to the 144th edition of The Java(tm) Specialists' Newsletter, sent to you from the Island of Crete. The last 6 months of living here on Crete have cost me about 4 years. When I arrived here, I looked 38, now people are starting to guess my age at 34. Perhaps by 2010, they will start asking me why I am not in school :-) I can strongly recommend spending 2 weeks here on holiday this summer and if you do, please look me up in Chania. A number of "Java Specialists" subscribers have already done this and we typically ended up lunching at the quaint little beach restaurant at Kalathas.
As from July 2007, I will be offering Java code reviews for your team to get an expert's viewpoint of your Java system.
Over the years, I have done several Java code reviews at various companies. Often Java developers were apprehensive at the thought of having a Java expert look at what they had produced. Imagine how pleasantly surprised they were when I complimented them on what they had produced (not always)? The code review gives me an opportunity to then present Java code and design improvements that help to make your Java system easier to maintain in future. This leads to big cost savings that quickly exceed the initial outlay for the code review.
javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.
At the Sun Tech Days in London (March 2007), I was suckered into participating in a Java Black Belt competition. I studiously avoid public contests like that, since I do not want to be upstaged by a younger, smarter participant. On my first attempt, I scored 4/5. For some reason, seeing my name on top discouraged some worthy contestants from even trying, which made me win the first round by default. All that they had to do was score 5/5 and I would have come second or third. The questions were quite interesting though, and I would recommend giving it a try if you see their stall at one of the Java conferences.
As a prize, I got to choose a book from a wonderful display of Java books. I had paged through the Java Puzzlers [ISBN 032133678X] book before at the Sun Tech Days in Johannesburg and of course, had heard a lot about it. Whenever I published really obscure ideas, readers of The Java(tm) Specialists' Newsletter would point me to the Java Puzzlers book, so this was an obvious choice.
Authors Dr Joshua Bloch and Dr Neal Gafter are fellow Java Champions. They work for Google, but used to be employed by Sun Microsystems. Joshua Bloch wrote a large chunk of code in the JDK and Neal Gafter was working on the Java compiler. They are exceedingly smart and each has a PhD in Computer Science.
I started reading the book whilst on the treadmill at the local Greek gym, which opens at 10:00 and closes between 13:00 and 16:00. The only gym in the world with those hours. Since I was a bit distracted, I flunked a few of the easier questions at the beginning of the book.
Here is a warning. Make sure that you spend a few minutes on each puzzle before attempting the answer, otherwise it has a good chance of being incorrect.
Overall, out of 95 questions, I got 69 correct, 4 partly correct and 22 completely wrong. I would love to hear of any readers who got 95 questions correct (Joshua and Neal, you're exluded, ok)! If you let me know, I will post your name in the next newsletter as a token of fame.
You might be wondering to yourself - why is Heinz even reviewing this book, which is already on the bestseller list and which we all own? Well, it took a Java Black Belt competition to motivate me to get hold of this book, and if you are like me, you might need additional inspiration to put down the $28.79 [ISBN 032133678X] .
There are two puzzles that I would like to discuss in this newsletter. The first involves throwing checked exceptions in an unchecked fashion. The second involves some threading and locking issues. Warning - contains spoilers!
This puzzle asks us to find at least two ways to throw exceptions, circumventing the exception checking. They give this as a third option:
// don't do this - circumvents exception checking! public static void sneakyThrow(Throwable t) { Thread.currentThread().stop(t); }
I must admit, this one had me stumped. I did not know how we could throw checked exceptions without the compiler picking it up and without doing the compile and switch trick.
Joshua and Neal gave clues that it was possible to do this using no deprecated methods and another way using Java 5 features.
The first approach uses a deficiency in the
Class.newInstance()
method. The
Constructor.newInstance()
method converts any
exceptions to an InvocationTargetException
, but the
Class.newInstance()
simply passes the exception
along. Here is their approach:
public class Thrower { private static Throwable t; private Thrower() throws Throwable { throw t; } public static synchronized void sneakyThrow(Throwable t) { Thrower.t = t; try { Thrower.class.newInstance(); } catch (IllegalAccessException e) { throw new IllegalArgumentException(e); } catch (InstantiationException e) { throw new IllegalArgumentException(e); } finally { Thrower.t = null; // avoid memory leak } } }
We need a no-args constructor to exploit this
weakness in Class.newInstance()
, which is why
we use a static variable to keep the actual throwable
instance. This is how we would call the
sneakyThrow()
method in our code:
public void diddleDum() { System.out.println("Oh I'm so innocent"); IOException exception = new IOException("hehe"); Thrower.sneakyThrow(exception); }
One of the limitations of this solution is that if you try to
throw InstantiationException
or
IllegalAccessException
, these will be caught in
the sneakyThrow() method and will thus cause an
IllegalArgumentException instead.
Instead of synchronizing statically, we could also use ThreadLocal to achieve a similar except, but without blocking all threads calling this method. Here is how you could do that:
public class ThrowerConcurrent { private static ThreadLocal<Throwable> throwables = new ThreadLocal<Throwable>(); private ThrowerConcurrent() throws Throwable { Throwable throwable = throwables.get(); throwables.remove(); // avoid memory leak throw throwable; } public static void sneakyThrow(Throwable t) { throwables.set(t); try { ThrowerConcurrent.class.newInstance(); } catch (IllegalAccessException e) { throw new IllegalArgumentException(e); } catch (InstantiationException e) { throw new IllegalArgumentException(e); } } }
The lesson to learn from this code is that you need to be
aware that Class.newInstance
can throw
checked exceptions that it does not declare.
The next approach uses generics to achieve the same effect, although in a completely different approach. For maximal compatibility, generics are implemented by type erasure: Generic type information is checked at compile but not at run time. We all know this already, but this approach exploits that to throw checked exceptions:
public class TigerThrower<T extends Throwable> { public static void sneakyThrow(Throwable t) { new TigerThrower<Error>().sneakyThrow2(t); } private void sneakyThrow2(Throwable t) throws T { throw (T) t; } }
The compiler warns you about the throw (T) t;
since this is an unchecked cast. This warning tells us that
the cast will not be checked at run time. Unchecked warnings
are dangerous, and should be eliminated from your code.
So now you know how to throw checked exceptions from a context that does not declare them. This is just for interest and has no practical application. It will definitely cause me to raise an eyebrow, if I spot this technique used during a code review of your Java system!
This puzzle was nicely obscured, and I walked into the trap
like a sheep led to slaughter. In the code, they do
something that I always try to avoid; they use
this
as a lock to synchronize on.
I already mentioned this problem in in a newsletter written in 2001.
Consider this code - what is the output?
import java.util.*; public class Worker extends Thread { private volatile boolean quittingTime = false; public void run() { while(!quittingTime) { pretendToWork(); } System.out.println("Beer is good"); } private void pretendToWork() { try { Thread.sleep(300); // Sleeping on the job? } catch (InterruptedException e) { } } // It's quitting time, wait for worker - // Called by good boss synchronized void quit() throws InterruptedException { quittingTime = true; join(); } // Rescind quitting time - Called by evil boss synchronized void keepWorking() { quittingTime = false; } public static void main(String[] args) throws InterruptedException { final Worker worker = new Worker(); worker.start(); Timer t = new Timer(true); // Daemon thread t.schedule(new TimerTask() { public void run() { worker.keepWorking(); } }, 500); Thread.sleep(400); worker.quit(); } }
It would make most people scratch their head for at least a few minutes. We start a worker thread that works - or at least pretends to work - until quitting time. Then the program schedules a timer task representing an evil boss who tries to make sure that it's never quitting time. Finally, the main thread, representing a good boss, tells the worker when it's quitting time and waits for the worker to finish.
At first glance, it looks as if at the following times things happen:
quit()
method. It acquires the lock to
this
, thus preventing other threads
from getting that lock. It then sets
quittingTime
to true
and joins the worker thread, thus waiting for it to
complete.keepWorking()
method, but cannot because the main thread still owns the
lock to this
.true
and quits, thus letting the main thread (good boss) also
complete. Since the evil boss is a daemon (thread), he
also dies.
Alas, that is not what happens. If you run the code, you
notice that the program just hangs up. A thread dump will
show you that the worker thread is still pretending to work
and the main thread is trying to complete the call to
join()
.
Why does this happen?
The call to join()
is itself
synchronized
and internally calls the
wait()
method on the object. Since Worker
extends Thread
, this
refers to the thread and to the worker at the same time.
The solution to this problem is to never synchronize on this or on whole methods. Always use a separate lock object, or even the new Java 5 locks.
In this "BetterWorker", I have changed the Worker to not inherit from Thread (favour composition over inheritance) and I use specific lock objects:
import java.util.*; public class BetterWorker { private volatile boolean quittingTime = false; private final Object quittingTimeLock = new Object(); private Thread workerThread = new Thread(new Runnable() { public void run() { while (!quittingTime) { pretendToWork(); } System.out.println("Beer is good"); } }); public void start() { workerThread.start(); } private void pretendToWork() { try { Thread.sleep(300); // Sleeping on the job? } catch (InterruptedException e) { } } // It's quitting time, wait for workerThread - // Called by good boss void quit() throws InterruptedException { synchronized (quittingTimeLock) { quittingTime = true; workerThread.join(); } } // Rescind quitting time - Called by evil boss void keepWorking() { synchronized (quittingTimeLock) { quittingTime = false; } } public static void main(String[] args) throws InterruptedException { final BetterWorker worker = new BetterWorker(); worker.start(); Timer t = new Timer(true); // Daemon thread t.schedule(new TimerTask() { public void run() { worker.keepWorking(); } }, 500); Thread.sleep(400); worker.quit(); } }
The code is still not terribly clear and should be rewritten entirely to represent what we are trying to achieve - to have a nice cold beer!
Some of the lessons we can learn from this:
The book is filled with information like this, which experienced Java developers should know. Some puzzles are a bit theoretical - not something that a programmer would do in real life. Also, a good IDE with syntax highlighting should immediately highlight some of the problems in the puzzles.
However, all in all, Java Puzzlers [ISBN 032133678X] belongs on your bookshelf, together with Effective Java [ISBN 0201310058] , Head First Design Patterns, Java Concurrency in Practice and Java Generics and Collections.
Don't forget to let me know if you got all 95 puzzles right - I would love to discover such a programmer!
Kind regards
Heinz
We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)
We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.