If you want to create an object in Java there is only one way: use a constructor.

Constructors

Constructors in Java are different from all other methods. They don’t have a return type and can’t be invoked, only using the new keyword. Other tasks performed by constructors are:

  1. Initialisation of class variables
  2. Call the default contructor of the superclass if no constructor is present
  3. Initialisation of instance variables
  4. Execution of constructor body

Here is a common example of a constructor in Java:


public class Person {

	//Two mandatory immutable fields
	private final String firstname;
	private final String lastname;
	
	//Constructor to set the final fields:
	public Person(String firstname, String lastname) {
		this.firstname = firstname;
		this.lastname = lastname;
	}

	...

If you want to create an immutable object in Java you need to have a constructor to initialise the final fields. Lets look at another example:

		Person person = new Person("Roy", "van Rijn", 1983, 200, 95.0, 12.5);

Immediately a problem becomes clear… if you read the code you have absolutely no idea what all the arguments mean. What is 200? What is 95.0? We have to look at the API or open the code of Person to see what arguments we can supply or have been supplied. Thankfully there is a design pattern that solves this problem, the Builder pattern.

Builder pattern

The builder pattern is an ‘object creation software design pattern’. It can be used to create a immutable objects in a fluent, readable way.


		Person me = new Person
				.PersonBuilder("Roy", "van Rijn")
				.birthYear(1983)
				.length(200)
				.weight(95.0) // This is what all these numbers mean!
				.shoeSize(12.5)
				.build();

Reading this code is much clearer, we don’t have to guess what the arguments mean, it is crystal clear. So we’ve got a good solution, right? Well, not really, I’ve got a big problem with the Builder pattern. For a simple immutable object as the Person above with just six fields we need the following code:

public class Person {

	// The immutable fields
	private final String firstname;
	private final String lastname;
	private final int birthYear;
	private final int length;
	private final double weight;
	private final double shoeSize;
	
	// The private hidden constructor with all fields:
	private Person(String firstname, String lastname, int birthYear, int length, double weight, double shoeSize) {
		this.firstname = firstname;
		this.lastname = lastname;
		this.birthYear = birthYear;
		this.length = length;
		this.weight = weight;
		this.shoeSize = shoeSize;
	}
	
	// A second Builder class with all the fields listed again:
	public static class PersonBuilder {
		
		private String firstname;
		private String lastname;
		private int birthYear;
		private int length;
		private double weight;
		private double shoeSize;
		
		public PersonBuilder(String firstname, String lastname) {
			this.firstname = firstname;
			this.lastname = lastname;
		}
		
		// All 'setters' with a fluent interface:
		public PersonBuilder birthYear(int birthYear) {
			this.birthYear = birthYear;
			return this;
		}
		public PersonBuilder length(int length) {
			this.length = length;
			return this;
		}
		public PersonBuilder weight(double d) {
			this.weight = d;
			return this;
		}
		public PersonBuilder shoeSize(double shoeSize) {
			this.shoeSize = shoeSize;
			return this;
		}
	
		// Finally a build method that calls the hidden constructor:
		public Person build() {
			return new Person(firstname, lastname, birthYear, length, weight, shoeSize);
		}
		
	}

Woah… that is a stupendous amount of code just for a better readable immutable way of object construction. I don’t have a good solution for this problem, the Java language doesn’t have a good way to construct objects (especially immutable objects) in a readable manner. Constructors end up having a lot of confusing nameless arguments; or you’ll have to write a huge Builder class with a nice fluent interface.

The Java language is constantly evolving and there are now proposals to add ‘value types’ in Java. Reading through the proposal it seems the only way to construct the value type will be using the constructor, but I’m afraid this will quickly become a burden again. I’d love to have a better way to construct objects and (in the future) values, although I have no idea what it should look like. I’d love to have a fluent way of object creation without having to code a big Builder class, preferably in the language itself.

Would it be possible to change to language in a backwards compatible way to allow this?

One possibility would be to ‘steal’ from other languages, for example Moose Perl:

public class Person {

	private final String firstname;
	private final String lastname;
	private int birthYear;
	private int length;
	private double weight;
	private double shoeSize;
	
        // Full constructor
	public Person(String firstname, String lastname, int birthYear, int length, double weight, double shoeSize) {
		this.firstname = firstname;
		this.lastname = lastname;
		this.birthYear = birthYear;
		this.length = length;
		this.weight = weight;
		this.shoeSize = shoeSize;
	}

...
// Made up syntax, similar to Moose, providing syntactic sugar.
// Leaves the other fields null, compile error if final fields aren't set.
Person me = new Person(firstname => "Roy", lastname => "van Rijn", birthYear => 1983);

This has the readability advantage and has the flexibility of the Builder pattern (not needing dozens of overloaded constructors).

Would something like this be a good addition to the Java language?

Tagged with:
 
  • Patrick van Dissel

    What about AST transformation annotations like groovy has, eg. @Immutable (http://groovy.codehaus.org/Immutable+transformation). But then something like an @Builder which generates the builder code, supporting additional metadata annotations on properties for tuning the generated builder code

  • Jan-Kees van Andel

    I hacked this thing together a couple of years ago. By far not perfect, but a nice example of a solution:
    https://code.google.com/p/make-builder/

    A fully supported, debuggable, non-code-generating language feature would be much nicer of course!