The new Certification Class of REST With Spring is out:

>> CHECK OUT THE COURSE

1. Overview

The Kotlin language introduces the concept of Data Classes, which represent simple classes used as data containers and do not encapsulate any additional logic. Simply put, Kotlin’s solution enables us to avoid writing a lot of boilerplate code.

In this quick article, we’ll take a look at Data Classes in Kotlin and compare them with their Java counterparts.

2. Kotlin Setup

To get started setting up the Kotlin project, check our introduction to the Kotlin Language tutorial.

3. Data Classes in Java

If we wanted to create a Movie entry in Java, we’d need to write a lot of boilerplate code:

public class Movie {

    private String name;
    private String studio;
    private float rating;
    
    public Movie(String name, String studio, float rating) {
        this.name = name;
        this.studio = studio;
        this.rating = rating;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getStudio() {
        return studio;
    }

    public void setStudio(String studio) {
        this.studio = studio;
    }

    public float getRating() {
        return rating;
    }

    public void setRating(float rating) {
        this.rating = rating;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result + Float.floatToIntBits(rating);
        result = prime * result + ((studio == null) ? 0 : studio.hashCode());
        
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        
        if (obj == null)
            return false;
        
        if (getClass() != obj.getClass())
            return false;
        
        Movie other = (Movie) obj;
        
        if (name == null) {            
            if (other.name != null)
                return false;
            
        } else if (!name.equals(other.name))
            return false;
        
        if (Float.floatToIntBits(rating) != Float.floatToIntBits(other.rating))
            return false;
        
        if (studio == null) {
            if (other.studio != null)
                return false;
            
        } else if (!studio.equals(other.studio))
            return false;
        
        return true;
    }

    @Override
    public String toString() {
        return "Movie [name=" + name + ", studio=" + studio + ", rating=" + rating + "]";
    }
}

86 lines of code. That’s a lot to store only three fields in a simple class.

4. Kotlin Data Class

Now, we’ll create the same Movie class, with the same functionalities, using Kotlin:

data class Movie(var name: String, var studio: String, var rating: Float)

As we can see, that’s massively easier and cleaner. Constructor, toString(), equals(), hashCode(), and additional copy() and componentN() functions are generated automatically.

4.1. Usage

A data class is instantiated the same way as other classes:

val movie = Movie("Whiplash", "Sony Pictures", 8.5F)

Now, the properties and functions of are available:

println(movie.name)   //Whiplash
println(movie.studio) //Sony Pictures
println(movie.rating) //8.5

movie.rating = 9F

println(movie.toString()) //Movie(name=Whiplash, studio=Sony Pictures, rating=9.0)

4.2. Copy Function

The copy() function is created, in case that we need to copy an object altering some of its properties but keeping the rest unchanged.

val betterRating = movie.copy(rating = 9.5F)
println(betterRating.toString()) // Movie(name=Whiplash, studio=Sony Pictures, rating=9.5)

Java doesn’t provide a clear, native way for copying/cloning objects. We could use the Clonable interface, SerializationUtils.clone() or a cloning constructor.

4.3. Destructuring Declarations

Destructuring Declarations allow us to treat objects properties as individual values. For each property in out data class, a componentN() is generated:

movie.component1() // name
movie.component2() // studio
movie.component3() // rating

We can also create multiple variables from the object or directly from a function – it’s important to remember about using brackets:

val(name, studio, rating) = movie

fun getMovieInfo() = movie
val(namef, studiof, ratingf) = getMovieInfo()

4.4. Data Class Requirements

In order to create a data class, we have to fulfill the following requirements:

  • The primary constructor needs to have at least one parameter
  • All primary constructor parameters need to be marked as val or var
  • Data classes cannot be abstract, open, sealed or inner
  • (before 1.1.) Data classes may only implement interfaces

Since 1.1, data classes may extend other classes.

If the generated class needs to have a parameterless constructor, default values for all properties have to be specified:

data class Movie(var name: String = "", var studio: String = "", var rating: Float = 0F)

5. Conclusion

We’ve seen Data Classes in Kotlin, their usage and requirements, the reduced amount of boilerplate code written, and comparisons with the same code in Java.

If you want to learn more about Kotlin, check articles such as Kotlin Java Interoperability and the already mentioned Introduction to the Kotlin Language.

The full implementation of these examples can be found in our GitHub project.

Go deeper into building a REST API with Spring:

>> CHECK OUT THE COURSE

Leave a Reply

4 Comments on "Data Classes in Kotlin"

Notify of
avatar
Sort by:   newest | oldest | most voted
Dusan Odalovic
Guest
Thanks for the article, with some remarks: The data keyword, used in our Kotlin class, automatically generates property accessors, constructors, toString(), equals(), hashCode() and the useful copy() and componentN() functions. * Property accessors and constructors are not generated due to `data` If the generated class needs to have a parameterless constructor, default values for all properties have to be specified: data class Movie(var name: String = "", var studio: String = "", var rating: Float = 0F) That’s not entirely true, this is the case to avoid defining default values in primary constructor: data class Person(val name: String, var age:… Read more »
Grzegorz Piwowarek
Guest

Thanks, we will fix that

Sam Mizanin
Guest

Well the syntax is cleaner but does kotlin give me any performance advantages over Java. If its the case of just Data classes then there are libraries like Project Lombok to deal with these to make your Pojos concise. Multi variable assignment is cool and straight out of Python.

Grzegorz Piwowarek
Guest

Here are some valuable insights into the Kotlin performance https://sites.google.com/a/athaydes.com/renato-athaydes/posts/kotlinshiddencosts-benchmarks

Yeah, Project Lombok and Vavr are absolutely essential for modern Java development. Multi variable assignment was there long before Python 🙂

wpDiscuz