Data classes in Kotlin
Tags: 100daysofcode, kotlin, java
Published: 2017-01-04 08:36:25

---
title: Data classes in Kotlin
published: true
description: 
cover_image: 
tags: 100daysofcode, kotlin, java
---
(Crazy busy day today, so simple article to meet my quota. Sorry)

I mentioned before about Kotlin being significantly streamlined as compared to Java. And one of the most obvious places it achieves this, that you are likely to see very early on, is in Data Classes.

Data classes are just classes. There's nothing special about them from that point. The actual "data" keyword was originally nothing more than an annotation that the compiler saw and reacted to. (I'm honestly not sure if this is still the case I'm afraid). As such, they can do (almost) anything that a normal class can do.

The point of Data Classes is that - believe it or not - they are meant to represent data, and not functionality. This is the definition of a Java Bean from Java-land. And that is exactly what they are. Only significantly more streamlines. When you add the "data" keyword (or annotation, or whatever it is) in front of the class definition, what you are telling the compiler to do is:

* Generate a class
* With this set of fields
* With getters (and optionally setters) for every field
* With an `equals` and `hashCode` method that is correct
* With a `toString` method that is correct
* With a `copy` method
* With a set of `componentN` methods

The first three of those are just part of how Kotlin defines classes anyway. That's nothing special. It's the other 4 that are where data classes really come into it.

Writing `equals`, `hashCode` and `toString` methods isn't hard. Writing them *correctly* can be though. But even then, most of the time people either have their IDE generate them automatically or else they use something like Commons-Lang Equals/HashCode/ToStringBuilder classes. And that's fine, but not without cost. The generated ones from the IDE will get stale as soon as the class changes, unless you remember to keep them updated. The Builder classes will either suffer the same problems, or else will use reflection with the performance cost that incurs.

The final set of methods are simply some helper methods. The `copy` method lets you take one object, and create a new one with the same values. Or with *some* of the same values. You can selectively pick and choose which values you want to replace with new ones. For example:
```kotlin
val user = User(username = "graham", email = "my.email@example.com", banned = false)
val copiedUser = user.copy(email = "my.real.email@example.com)
```

In this case, copiedUser has:
* username = "graham"
* email = "my.real.email@example.com"
* banned = false

And you only had to specify one of those values.

The `componentN` methods are used by Destructuring, which is a topic in itself. Simply put though, it lets you take a class and decompose it into individual fields. This is very useful in a few places - such as pattern matching - when you don't care about the class itself but just the individual fields.

In short though, data classes aren't anything special. They don't really *do* anything. They just allow you to not write a lot of boilerplate for what are essentially generated methods. You can write a Java Bean with a number of fields, and get all of the correct JavaBean methods for everything you need, and a few more on top, in a single line of code. To steal an example from Reddit, it's turning this:
```kotlin
public class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String component1() {
        return name;
    }

    public int component2() {
        return age;
    }

    public User copy() {
        return new User(name, age);
    }

    public User copy(String newName) {
        return new User(newName, age);
    }

    public User copy(String newName, int newAge) {
        return new User(newName, newAge);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        if (age != user.age) return false;
        return name != null ? name.equals(user.name) : user.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
```

into this:
```kotlin
data class User(val name: String, val age: Int)
```