Running on Java 22-ea+15-1134 (Preview)
Home of The JavaSpecialists' Newsletter

144Book Review: Java Puzzlers

Author: Dr. Heinz M. KabutzDate: 2007-05-16Java Version: 1.4Category: Book Review
 

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.

Book Review: Java Puzzlers [ISBN 032133678X]

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!

Puzzle 43: Exceptionally Unsafe

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!

Puzzle 77: The Lock Mess Monster

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:

  • 300ms The worker thread checks the volatile boolean and continues working.
  • 400ms The good boss (main thread), calls the 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.
  • 500ms The evil boss now tries to call the keepWorking() method, but cannot because the main thread still owns the lock to this.
  • 600ms The worker thread checks the volatile boolean for the second time, sees it is 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:

  • Don't assume anything about what a library class will or won't do with locks.
  • If you need full control over a lock, make sure that no one else can gain access to it.

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

 

Comments

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)

When you load these comments, you'll be connected to Disqus. Privacy Statement.

Related Articles

Browse the Newsletter Archive

About the Author

Heinz Kabutz Java Conference Speaker

Java Champion, author of the Javaspecialists Newsletter, conference speaking regular... About Heinz

Superpack '23

Superpack '23 Our entire Java Specialists Training in one huge bundle more...

Free Java Book

Dynamic Proxies in Java Book
Java Training

We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.

Java Consulting

We can help make your Java application run faster and trouble-shoot concurrency and performance bugs...