Thursday, March 26, 2015

It's time to make immutability the default

Right. I have to get this off my chest. A follow-on from my habitual coding observation in my previous article.

How many people habitually write Java code like this? (Clue: I see it a lot)

public class Article {
    private String title;
    private String author;
    private List tags;

    public void setTags(List tags) {
        this.tags = tags;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }

    public List getTags() {
        return tags;
    }
}

Then you can create an object an use it with something like:
    Article article = new Article();
    article.setAuthor("Cam M. Bert");
    article.setTitle("French Cheeses");
    article.setTags(Collections.asList("cheese", "food"));

    // etc etc

Great, assuming that you want to allow changes to the object later. But if you have no explicit requirement to change anything, then you have left the door wide open to abuse. Your setters are public. You have written too much code.

OK, let's try something else and lock the door. Wouldn't it be nice if we created the object in the correct state from the off, all ready to use, rather than having to construct then initialise. We end up with something like:
public class Article {
    private String title;
    private String author;
    private List tags;

    public Article(String title, String author, List tags) {
        this.title = title;
        this.author = author;
        this.tags = tags;
    }

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }

    public List getTags() {
        return tags;
    }
}
A bit better. Remember, you don't have any explicit requirement to change values so do not need any mutator methods. The tags List object is still open to abuse, but hey-ho....

But I can't help thinking this is a very short hop from:

public class Article {
    public final String title;
    public final String author;
    public final List tags;

    public Article(String title, String author, List tags) {
        this.title = title;
        this.author = author;
        this.tags = Collections.unmodifiableList(tags);
    }
}
Less code to read, easy access to immutable fields.

My point is the following. If you have no definite requirement to change the values on a POJO, then make it immutable from the start! Only introduce mutator methods as they are required.

One final thing - yes, you can produce a similar result by using frameworks like Lombok to hide the 'getXyz()' methods, but why introduce further complexity of a framework when it can be done so elegantly natively?

There. I feel better now :-)


Note - some of the code is appearing with </string> annotations - no idea why. Seems to be a quirk of the Google Blogger editor
Note #2 - the </string> annotations appear to be a Chrome issue. Oh the irony! :)


3 comments:

Gus Power said...

Or, in Groovy:

@Immutable
@TupleConstructor
class Article {
String title
String author
List tags
}

Chris said...

Unfortunately not possible in not-Groovy Java world :-(

cy6erGn0m said...

In Kotlin you can simply write

data class Article(val title: String, val author: String, val tags: List)

So you get immutable "data" class with all required hashcode, equals, toString and nullability