Books: Java

EffectiveJava-Bloch

When I was writing the last post, I realized how much I used to be in awe of Effective Java [Bloch, 2017]. It was a book that covered what no other did. It wasn’t just coding — there’re plenty of books where one could learn “Your first Java Program” and beyond, and throw an air punch. It wasn’t also about language syntax and semantics — Java Complete Reference [Schildt, 2017] fitted the bill there*, or OOPs (every other Java book started with OOPs concepts). Rather, Effective Java covered the basics of writing elegant Java code, and as a by-product, also underlined how easy was it to be swayed away by ‘convention’. I wouldn’t recommend it as a Java learner’s first book. But it should very well be one’s second Java book and the one that she/he would keep revisiting throughout the programming career.

Ever since I’ve picked it up again, it’s become tough to keep it aside. With each of its topic, I realize, over time, how much have I drifted away from the delight of writing good code, and how much do I need to still learn.
Go read it now if you haven’t had a chance yet. What’s more, the much-awaited 3/E, which covers Java 7, 8 and 9, is out now!

While on this topic, let me talk about another one of my favourite books on Java — Thinking in Java [Eckel, 1998].

ThinkingInJava-Eckel

This is the book which I considered as a Java developer’s Bible at one point in time. Since there are no new editions after the 4/E, the syntactical parts might be a bit obsolete now. But still, in my opinion, it’s the best book to get one’s (Java & OOPS) fundamentals in place.

* I have always found Java Complete Reference a bit too elaborate to my liking. Most of which is about the language syntax and semantics. All of that might have been useful in the early days of the Internet when it wasn’t that easy to look up things online. But I doubt if that’s needed now.

The elegance of Builder pattern

Paraphrasing Josh Bloch in Effective Java [Bloch, 2017, Item 2]:

While creating objects, in cases where the number of optional parameters of an object is considerable, say 4 or more, one might think of static factory methods [Bloch, 2017, Item 1] as a solution — but they’re more suitable for a small set of parameters. When there are several optional params, static factories cannot be used as it’s cumbersome to imagine and cater to all possible parameter combinations. Another approach that’s proposed in such cases is using JavaBeans but it has its own shortcomings.

Therefore, we usually go with multiple (telescoping) constructors for such requirements. For example:

public Cake(int oilTbsp, int flourMg){
  this(oilTbsp, flourMg, 0);
}

public Cake(int oilTbsp, int flourMg, int eggCount){
  this(oilTbsp, flourMg, eggCount, 0);
}

public Cake(int oilTbsp, int flourMg, int eggCount, int bakingPowderMg){
  this(oilTbsp, flourMg, eggCount, bakingPowederMg);
}

//...

Such implementations, although purpose-serving, are a bit contrived in that the class client needs to tally the parameters accurately. Consider a large parameter list, and this would be an overkill.

A variation of Builder pattern [Gamma, 1995], is what Bloch suggests, for such cases. In it, a builder class is a static member of the class it builds, for example:

public class Cake{
  //...
  private Cake(Builder builder){
    //...
  }

  public static class Builder{
    //...
  }
}

Since the original constructor is hidden, the client first gets a reference to the Builder class — passing all the required params to its constructor or static factory. The client then calls setters on the returned builder object to set the optional parameters of interest. Finally, the client makes a call to the build() method to generate an immutable object.
Since the builder setter methods return the builder itself, the invocations can be chained, like so:

// Set only the parameters of interest
Cake cake = new Cake.Builder(350, 45).egg(2).sugar(240).cocoa(35)...build();

As is apparent, this is intuitive as well as concise.

A builder can be further enhanced by enabling it to build more than one object, based on parameters. One has to be cautious, however, to disallow building an object of an inconsistent state. This can be ensured by validating the passed parameters as early as possible and throwing a suitable exception.

Builders can also be used to automate certain tasks and fill in the fields. For example, autoincrementing the object Id, etc.

As Josh Bloch advises, we should be using Builders as often as possible, especially in cases where the number of parameters is significant. They’re a simple and elegant alternative to telescoping constructors or JavaBeans.

[Full implementation of the Cake builder example is here.]