Shekhar Gulati is a Java Consultant with over 5 years experience.He is currently working with Xebia India an Agile Software Development company.The postings on this site and on his blog are his own and do not necessarily represent opinion of his employer. His own blog is at http://whyjava.wordpress.com/ and you can follow him on twitter here. Shekhar has posted 25 posts at DZone. View Full User Profile

Achieving Immutability with Builder Design Pattern

08.03.2010
| 19233 views |
  • submit to reddit

One piece of advice from Effective Java is that you should make your classes Immutable unless there is a good reason to make them mutable. If a class cannot be made immutable, limit its mutability as much as possible. Immutable classes define objects which, once created, never change their state. All the state information is provided at the time the object is constructed and it does not change for the lifetime of the object.

Why should we write Immutable classes?

Immutable classes offer many advantages over mutable classes. These are:

  1. An immutable object is simple and easier to use as it can be in only one state, the state in which it was created.
  2. They are inherently thread safe, i.e. they do not require synchronization.
  3. The objects of immutable classes can be shared freely. For example, Boolean class reuses its existing instances TRUE and FALSE and whenever you call Boolean.valueOf method it gives you the already created instances.

Creating an Immutable class

A simple immutable class can be like this:

public final class User {

private final String username;
private final String password;

public User(String username, String password) {
this.username = username;
this.password = password;
}

public String getUsername() {
return username;
}

public String getPassword() {
return password;
}
}

 

This class is immutable because:

  1. It does not provide setter methods or mutators.
  2. The Class can't be extended because it is final. This could have also been done by making the constructor private.
  3. Fields of the class are all final and private.

It is important to note that this class was very simple with only two fields.  In most of the classes in our real applications there are more than two fields. Also, most of these fields are not mandatory for object creation. For example, a user in a real application will have a username, password, firstname, lastname, creationDate, emailAddress, etc., but for user creation here, only a username and password are required. So, we design our class as shown below:

public final class User {

private final String username;
private final String password;
private String firstname;
private String lastname;
private String email;
private Date creationDate;

public User(String username, String password) {
this.username = username;
this.password = password;
creationDate = new Date();
}

public String getUsername() {
return username;
}

public String getPassword() {
return password;
}

public String getFirstname() {
return firstname;
}

public void setFirstname(String firstname) {
this.firstname = firstname;
}

public String getLastname() {
return lastname;
}

public void setLastname(String lastname) {
this.lastname = lastname;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}

public Date getCreationDate() {
return new Date(creationDate.getTime());
}
}

 

This class is not immutable because it has mutators, i.e. setters. So, instances of this class can be modified after creation.  This approach has the disadvantage that objects can be in an inconsistent state part of the way through their construction and you have to put in extra effort to ensure thread safety.

Builder Design Pattern comes to the Rescue

According to Gof:

The Builder Pattern separates the construction of a complex object from its representation so that the same construction process can create different representations.

The builder design pattern provides a way for you to build complex immutable objects. The process is:

  1. The client calls a constructor (or static factory) with all the required parameters and gets a builder object.
  2. The client calls setter like methods to set each optional parameter of interest.
  3. Finally the client calls the build method to generate the object which is immutable.

Immutable User

public class ImmutableUser {

private final String username;
private final String password;
private final String firstname;
private final String lastname;
private final String email;
private final Date creationDate;

private ImmutableUser(UserBuilder builder) {
this.username = builder.username;
this.password = builder.password;
this.creationDate = builder.creationDate;
this.firstname = builder.firstname;
this.lastname = builder.lastname;
this.email = builder.email;
}

public static class UserBuilder {
private final String username;
private final String password;
private final Date creationDate;
private String firstname;
private String lastname;
private String email;

public UserBuilder(String username, String password) {
this.username = username;
this.password = password;
this.creationDate = new Date();
}

public UserBuilder firstName(String firsname) {
this.firstname = firsname;
return this;
}

public UserBuilder lastName(String lastname) {
this.lastname = lastname;
return this;
}

public UserBuilder email(String email) {
this.email = email;
return this;
}

public ImmutableUser build() {
return new ImmutableUser(this);
}

}

public String getUsername() {
return username;
}

public String getPassword() {
return password;
}

public String getFirstname() {
return firstname;
}

public String getLastname() {
return lastname;
}

public String getEmail() {
return email;
}

public Date getCreationDate() {
return new Date(creationDate.getTime());
}

}

 

You should also check the invariants in the build method and throw in an IllegalStateException if any attribute is invalid. This will ensure that the object is in a workable state once it is instantiated.

The client code will look like this :

public static void main(String[] args) {
ImmutableUser user = new ImmutableUser.UserBuilder("shekhar",
"password").firstName("shekhar").lastName("gulati")
.email("shekhargulati84@gmail.com").build();
}

 

In this way you build a complex object which is immutable and has all the advantages of immutable objects.

Note : Effective Java is a must read for every Java developer

Published at DZone with permission of its author, Shekhar Gulati.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Thomas Escolan replied on Tue, 2010/08/03 - 2:48am

I guess you missed a point in immutability description : 4 - more than being final and private, the accessible members of the class HAVE to be immutable also ; in this case, String members are... But what if we used something like user.getAddress().setStreet("changed state avenue") ?.. Have a good day.

Liran Mendelovich replied on Tue, 2010/08/03 - 2:58am in response to: Thomas Escolan

Is the Builder way better than do only one constructor which contain all the fields ?

Jeff Lin replied on Tue, 2010/08/03 - 4:25am in response to: Thomas Escolan

@Thomas Escolan

 Aren't Strings immutable?

Slava Lo replied on Tue, 2010/08/03 - 6:02am in response to: Thomas Escolan

I think the author demonstrated (maybe not explicitly) this in getCreationDate, where it actually returns a copy of Date rather than the actual value of a property.

Slava Lo replied on Tue, 2010/08/03 - 6:06am in response to: Liran Mendelovich

The problem with constructor which accepts all fields is that the list of parameters can get very long, and all the client code which uses the constructor will have to be changed every time new optional field is added or some field is removed.

It is also very easy to misplace the values passed to the constructor in case when they are of the same type (like firstname and lastname which would be both of type String)

Shekhar Gulati replied on Tue, 2010/08/03 - 7:54am in response to: Slava Lo

@Slava Yes that's correct. I didn't mentioned it explicitly but I showed it through Date. I will update the article to make it explicit.

Shekhar Gulati replied on Tue, 2010/08/03 - 8:02am in response to: Liran Mendelovich

Builder pattern makes sense when constructors of class has more parameters, and most of those parameters are optional. Builder also leads to clean client code as shown in the article.

Liran Mendelovich replied on Tue, 2010/08/03 - 8:39am in response to: Shekhar Gulati

So if some fields are optional, it's quite equivalent to make constructors for all the options ? (That can be many options - so many constructors - not so good, now the builder is making sense). But besides that, it's quite the same, right ? The client could have write the wanted options at the constructor or at the builder - and would still have to change the code if needed, right ?

Erin Garlock replied on Tue, 2010/08/03 - 10:57am

For other examples from the JDK, see the various Collections.synchronized* and Collections.unmodifiable* methods (e.g. Collections.unmodifiableMap(...))

In these cases, your code that builds up the initial collection is the builder.

Personally I'm not fond of the suggested pattern and naming conventions in this article: MutableThing, ImmutableThing, MutableThingBuilder.  Just simply ask for an Immutable copy from your mutable instance, or as the JDK Collections API uses, use a factory to get an Immutable version.

If you interfaced everything, then the code is even cleaner if you have a MutableObject interface and an ImmutableObject interface.  The only drawback being that a clever developer could try casting the immutable instance to a mutable one and it would work, but it may be worth it, especially if making an immutable clone (remember the old JDK Cloneable interface?) is expensive or just obfuscates things.

public interface MutableInterface {
void setName(String name);
}

public interface ImmutableInterface {
String getName();
}

public MyObject implements MutableInterface, ImmutableInterface {
...
public ImmutableInterface getImmutableMyObject(){
return (ImmutableInterface)this;
}
}

Shekhar Gulati replied on Tue, 2010/08/03 - 1:46pm in response to: Erin Garlock

@Erin I don't agree that this class is Immutable(if I understood your approach correctly) because state can get change between two getName calls. For example :-


public static void main(String[] args) {
MyObject obj = new MyObject();
obj.setName("shekhar");
ImmutableInterface immutableMyObject = obj.getImmutableMyObject();
System.out.println(immutableMyObject.getName());
obj.setName("hacker");
System.out.println(immutableMyObject.getName());
}

Output will be

shekhar

hacker

In this way, state of immutable object has changed so it is immutable. Can you please elaborate your approach may be I am missing something?

Erin Garlock replied on Tue, 2010/08/03 - 2:31pm in response to: Shekhar Gulati

The two interface method is not a guarantee since there are ways around it.  Like I said, this is useful where cloning is an expensive operation.

If you're interested in keeping both the mutable original and subsequent immutable clone, I'd have to ask why?  I think in the one or two cases that I have ever needed an immutable clone created from a mutable instance, the original was disposed of immediately.

I've seen much code that was written to circumvent someone from misusing on object, and forcing some very specific manner of usage.  Always there is a work around (sometimes called hacking).  Usually the "defensive" code just gets in the way and it's hard to read, understand, and maintain.  Generally speaking, it sort of begs the question, why is the rigidly specified usage encapsulated not in a single method?

Where cloning is expensive, one way to defend the side affect you showed in your example is not to create a new immutable instance, but to just set the original instance to an immutable state - makeImmutable().  The easiest way, not necessarily the best, is to have a simple boolean in each setter method:

if(notMutable) {
throw new UnsupportedOperationException(...);
}

I'm personally not a big fan of immutable objects to begin with - they have their place, but I find it rare.  Usually my argument is:

1. If I have an immutable object, then I know I can't change it, therefore I'm not going to try. 

2. But if I know I need an immutable object, why would I even try to change it to begin with?

3. If I really do need to change a value later on, I must need to, therefore I'm not going to use an immutable object.

I once asked one of my junior developers, how many safeguards and defenses are on a screwdriver to prevent you from using it as an icepick? 

 

Erin Garlock replied on Tue, 2010/08/03 - 2:36pm in response to: Erin Garlock

How many of our SpringBeans (assuming you use Spring) use properties instead of constructors?  And how many of those beans are made immutable after they have been created?  Theoretically they could be changed.

Erin Garlock replied on Tue, 2010/08/03 - 4:00pm in response to: Shekhar Gulati

First, I have to apologize for getting us off topic "builder for immutability" vs. immutability in general. 

I like the builder pattern, but not immutability because immutability, in addition to my previous arguments, is usually only a shallow clone.  The wrapper class might be immutable, but its contained objects may not be.  For example:

ComplexObject complexObject = new ComplexObject();
complexObject.setName("foo");
ImmutableObject immutableMyObject = ImmutableObject.Builder.complexObject(complexObject).build();

System.out.println(immutableMyObject.getComplexObject().getName());

complexObject.setName("bar");
System.out.println(immutableMyObject.getComplexObject().getName());

 

Output will be:

foo

bar

Do you have any suggestions on true immutability via a builder to prevent this?

I'd love to see a feature in java (and other languages) for cascading effects on empty interfaces, e.g. Cloneable, Serializable, and (hypothesized) Immutable.  More or less it would be something like java.lang.Object.cascadeImmutable().  And in those cases where we know there is a hard reason to prevent some action at design time we can then explicitly implement NotMutable (to defend against cascadeMutable()), etc.

It could be done with some weird dynamic proxy class magic.  Yeah, that's our magical builder pattern again.

Puran Singh replied on Tue, 2010/08/03 - 4:32pm

I think the title of this article is not appropriate, builder pattern doesn't make any guarantee that your object will be immutable it's just a better way then constructor with zillions of arguments to create an object. Immutable class is only immutable if all the objects contained by it are immutable too.. that's it.

1. all fields are final

2. all objects are immutable too.

3. getter methods only

 

 

 

Thomas Eichberger replied on Wed, 2010/08/04 - 1:37am

Ignoring the discussion here about what is immutable and what not, I like your article very much, because it shows very precisely how to use a builder to make (more or less) "immutable" objects. I think this is very important for Java beginners.

Of course all the fields of the created objects should have immutable types, too.

So I think I can give this article to junior developers to show them how it should be done :-)

 

Martin Below replied on Wed, 2012/09/12 - 1:35am

I've written an Eclipse Plugin that automatically generates Builders for both mutable and immutable classes. It's open source: http://mbelow.blogspot.de/2012/09/eclipse-plugin-for-creating-builders.html 

 

Phil Crow replied on Tue, 2013/11/26 - 5:30am in response to: Erin Garlock

The answer to making this work as an immutable object is to always make defensive copies to ensure immutability. If you pass in an object then store that object or retrieve that object from an "immutable" object, then it's not really immutable because it's contents can be changed by the reference to the object.

Something like this in the Builder will prevent someone from being able to change the state of a nested object by obtaining a reference to it:


   public ImmutableObjectBuilder complexObject(ComplexObject suppliedComplexObject) {
      ComplexObject persistedComplexObject = new ComplexObject();
      persistedComplexObject.setStringField(suppliedComplexObject
                                                 .getStringField);
      this.complexObject = persistedComplexObject;
      return this;
   }
   // end builder & builder methods
}

...
// ImmutableObject getters 
public ComplexObject getComplexObject(){
   return new ComplexObject().setStringField(this.complexObject
                                               .getStringField());
}


Further as I said, any call to the contents of the object field should return a copy of the complexObject  object, not the actual object. Passing the actual object allows manipulation of the internal state. 

This is detailed in Josh Bloch's Effective Java. 

While someone may not do that because they misuse the concept, that doesn't mean it shouldn't be done does it?

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.