Let's Code Kotlin: Goodbye Builders, Hello Data Classes
Tags: kotlin, android
Published: 2021-02-08 16:05:12

---
title: Let's Code Kotlin: Goodbye Builders, Hello Data Classes
published: true
description: Long gone are the days of Builder classes and their massive amount of boilerplate code. In this new era, Kotlin has given us Data Classes and I've never looked back. (Except to write this post, and let me tell you: the past was a scary place.)
tags: kotlin, android
cover_image: https://www.gatling.xyz/content/images/2021/02/Let-s-Code-Kotlin_-Data-Classes.png
canonical_url: https://www.gatling.xyz/blog/2021/02/08/kotlin-data-classes/
---

If it wasn't for auto-generation, I can't say I'd be a good programmer. Back when Java was my sole language used for Android apps, manually writing each and every getter and setter would have been the bane of my existence, and eventually my downfall. Potentially constructors, too. Android Studio luckily can generate them all for me, which is why I'm still alive today.

When I switched to Kotlin, I was amazed. So many things I had been creating for years with ~~too~~ so* many lines of code were now being reduced to a small handful for the necessities. 

[I've mentioned before](https://dev.to/gatlingxyz/makethechange-from-java-to-kotlin-2h24) about my love for this Kotlin feature, but it deserves its own post: Let's talk about Data Classes.

## The Java Way

In Java, you need to be *verbose*. 

```java
class Pizza {

    private Dough dough;
    private Sauce sauce;
    private Cheese cheese;
    private List<Topping> toppings = new ArrayList<>();

    private Pizza(Dough dough, Sauce sauce, Cheese cheese, List<Topping> toppings) {
        this.dough = dough;
        this.sauce = sauce;
        this.cheese = cheese;
        this.toppings = toppings;
    }

    static class Builder {
        private Dough dough;
        private Sauce sauce;
        private Cheese cheese;
        private List<Topping> toppings = new ArrayList<>();

        public Builder() {
            
        }
        
        public Builder(Pizza pizza) {
            this.dough = pizza.dough;
            this.sauce = pizza.sauce;
            this.cheese = pizza.cheese;
            this.toppings = pizza.toppings;
        }
        
        public Builder setDough(Dough dough) {
            this.dough = dough;
            return this;
        }

        public Builder setSauce(Sauce sauce) {
            this.sauce = sauce;
            return this;
        }

        public Builder setCheese(Cheese cheese) {
            this.cheese = cheese;
            return this;
        }

        public Builder setToppings(List<Topping> toppings) {
            this.toppings = toppings;
            return this;
        }

        public Pizza build() {
            return new Pizza(dough, sauce, cheese, toppings);
        }
    }

}
```

I never want to see that type of code again in my life. To build a pizza, we would do this:

```java
Pizza newOrder = new Pizza.Builder()
                .setDough(Dough.HAND_TOSSED)
                .setSauce(Sauce.EXTRA_NORMAL)
                .setCheese(Cheese.MOZZARELLA)
                .setToppings(Arrays.asList(Topping.BACON, Topping.JALEPENOS))
                .build();
```

All of that work to get something, admittedly, pretty. I can't really argue with the results: the builder pattern produces some nice looking code. It's been worth it in the past, but the amount of boilerplate code has always frustrated me.

If I wanted to add one more configuration to it — let's say we split up toppings to be `Meats` and `Vegetables` — then I have to:

1. Change `private List<Topping> toppings = new ArrayList<>();` in the class to reflect the split
2. Change the private constructor to handle the split
3. Duplicate the `toppings` split in the Builder
4. Remove `setToppings()` in the builder
5. Add two more `set`s to the builder to handle meats and vegetables.

Heaven forbid I want to add `uncookedToppings` to the configuration.

It's entirely too much and my brain hurts just thinking about it.

## The Kotlin Way

In Kotlin, there's a much simpler way to handle builders: not having one at all.

```kotlin
data class Pizza(val dough: Dough,
                  val sauce: Sauce,
                  val cheese: Cheese,
                  val toppings: List<Topping>) {
}
```

That *entire* Java class gets reduced to 5 lines; it could be 1 but this how I like to format my classes.

The code to make a pizza now turns into this:

```kotlin
val newOrder = Pizza(
                Dough.HAND_TOSSED, 
                Sauce.EXTRA_NORMAL, 
                Cheese.MOZZARELLA, 
                listOf(Topping.BACON, Topping.JALEPENOS)
)
```

Again, this could all end up on one line, but this is how I format my object initializations if three or more parameters being provided.

To be fair, you can do this in Java as well by removing the builder and allowing you to use the public constructor. And for simple cases, sure, that *could* be fine. But then if you have defaults for each value, you'd probably end up in a case where you have a million constructors letting you configure the pizza however you want: just set the dough and cheese, or just the sauce and dough. At this point, the Builder provides you with more flexibility by allowing you to set the defaults there, and if they aren't provided with one of the setters, it'll fallback to the default. 

But then we're back to using the Builder, and that's where my frustration comes in.

In Kotlin, you can provide the default value, too:

```kotlin
data class Pizza(val dough: Dough = Dough.NORMAL,
                  val sauce: Sauce = Sauce.NORMAL,
                  val cheese: Cheese = Cheese.MOZZARELLA,
                  val toppings: List<Topping> = listOf()) {
}
```

This is your standard pizza: regular dough, regular sauce, mozzarella cheese, and no toppings. 

```kotlin
val defaultPizza = Pizza()
```

Our plain cheese pizza is a simple `Pizza()`. 

Extra cheese? We can set just that.

```kotlin
val extraCheese = Pizza(cheese = Cheese.EXTRA_MOZZARELLA)
```

Hand-tossed with mushrooms? Easy, *and* you can call the toppings first then the dough, using Kotlin's Named Arguments.

```kotlin
val handTossedMushroom = Pizza(toppings = listOf(Topping.MUSHROOMS), dough = Dough.HAND_TOSSED)
```

## .copy

As an added bonus of data classes, they have a built-in `.copy()` method. In our Java example, we had to manually make a separate constructor that took in an old `Pizza` and set the values it held into our new builder, allowing us to change them.

```kotlin
Pizza updatedOrder = new Pizza.Builder(newOrder)
                .setCheese(Cheese.EXTRA_MOZZARELLA)
                .build();
```

In Kotlin, however, it's all *baked* in. (You get it? *Baked*? lol) And with the help of Named Arguments, you can only change the values you want to change.

```kotlin
val updatedOrder = newOrder.copy(cheese = Cheese.EXTRA_MOZZARELLA)
```

---

Data classes are absolutely amazing. For more information on them, visit the [official documentation](https://kotlinlang.org/docs/reference/data-classes.html). 

Anyone else love data classes as much as me? Leave a comment below and let me know how your life is better because of them. 😉