After moving from Java to Kotlin, I don’t see the need for builders anymore

Jon Gille
AndroidPub
Published in
3 min readJan 4, 2018

When writing Java code, I often found myself using the builder pattern.

There was typically two types of use cases when I wrote builders:

  • I had more than a few constructor parameters.
  • I needed to construct a lot of instances of X in tests, and I just wanted random (but overridable) values for the fields in X.

In Java I might have this POJO:

public class Customer {

public final String firstName;
public final String middleName;
public final String lastName;
public final boolean wantsAnnoyingNewsLetter;

public Customer(String firstName,
String middleName,
String lastName,
boolean wantsAnnoyingNewsLetter) {
this.firstName = firstName;
this.middleName = middleName;
this.lastName = lastName;
this.wantsAnnoyingNewsLetter = wantsAnnoyingNewsLetter;
}

}

And this builder (this would be a builder used in tests, otherwise there wouldn’t be any default values):

public class CustomerBuilder {

private String firstName = randomText();
private String middleName;
private String lastName = randomText();
private boolean wantsAnnoyingNewsLetter = true;

public CustomerBuilder withFirstName(String firstName) {
this.firstName = firstName;
return this;
}

public CustomerBuilder withMiddleName(String middleName) {
this.middleName = middleName;
return this;
}

public CustomerBuilder withLastName(String lastName) {
this.lastName = lastName;
return this;
}

public CustomerBuilder withWantsAnnoyingNewsLetter(boolean wantsAnnoyingNewsLetter) {
this.wantsAnnoyingNewsLetter = wantsAnnoyingNewsLetter;
return this;
}

public Customer build() {
return new Customer(this.firstName,
this.middleName,
this.lastName,
this.wantsAnnoyingNewsLetter);
}
}

To create an instance with the builder I would do:

Customer jon = new CustomerBuilder()
.withFirstName("Jon")
.withMiddleName("Ola")
.withLastName("Gille")
.build();

Or in tests perhaps something like:

Customer aRandomCustomer = new CustomerBuilder()
.withWantsAnnoyingNewsLetter(false)
.build();

Now all of this works fine, the code is readable and I can create Customer instances in tests without much effort. This is what I was after. But there’s quiet a bit of code I have to write (and read) to make all this happen (and this was a small class with only 4 fields after all, it gets worse for bigger classes of course).

How does Kotlin help with this? Well, first of all it supports named arguments and default values, which means that constructing a Customer instance can be readable and not very error prone even without a builder:

data class Customer(val firstName: String,
val middleName: String? = null,
val lastName: String,
val wantsAnnoyingNewsLetter: Boolean = true)

val jon = Customer(
firstName = "Jon",
middleName = "Ola",
lastName = "Gille"
)

What about tests where I want a simple way of creating customer instances? You can use something similar to a builder, but a much more concise version than the Java one:

class CustomerBuilder {

var firstName = randomText()
var middleName: String? = null
var lastName = randomText()
var wantsAnnoyingNewsLetter = true

fun build(modify: (CustomerBuilder) -> Unit): Customer {
modify(this)
return Customer(
firstName = firstName,
middleName = middleName,
lastName = lastName,
wantsAnnoyingNewsLetter = wantsAnnoyingNewsLetter
)
}
}

val aRandomCustomer = CustomerBuilder().build {
it
.wantsAnnoyingNewsLetter = false
}

Or, and I think I like this better, you can utilize named arguments and default values again:

data class CustomerTemplate(val firstName: String = randomText(),
val middleName: String? = null,
val lastName: String = randomText(),
val wantsAnnoyingNewsLetter: Boolean = true) {
fun buildCustomer() = Customer(
firstName = firstName,
middleName = middleName,
lastName = lastName,
wantsAnnoyingNewsLetter = wantsAnnoyingNewsLetter
)
}

val aRandomCustomer =
CustomerTemplate(wantsAnnoyingNewsLetter = false).buildCustomer()

I’m still fairly new to Kotlin and I’m sure there are even better ways of doing this, but this is just one out of many small things that in my opinion makes Kotlin much nicer to work with than Java.

--

--

Jon Gille
AndroidPub

Developer, problem solver and technical leader. Interested in leadership an product development, but still make sure to write code.