Kotlin Data Class

Filed Under: Kotlin

In this tutorial, we’ll look at Kotlin Data Class. If you haven’t read the Kotlin Classes post, we recommend you to do so before proceeding.

Kotlin Data Class

Kotlin Data Class
Do you get tired of writing thousands of lines of code for your POJO data classes in Java?

Every Java Programmer at some stage must have taken a note of the number of lines of code they need to write for classes that just need to store some data. Let’s see how a Book.java POJO class looks like:


public class Book {

    private String name;
    private String authorName;
    private long lastModifiedTimeStamp;
    private float rating;
    private int downloads;


    public Book(String name, String authorName, long lastModified, float rating, int downloads) {
        this.name = name;
        this.authorName = authorName;
        this.lastModifiedTimeStamp = lastModified;
        this.rating = rating;
        this.downloads = downloads;
    }

    public String getName() {
        return name;
    }

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

    public String getAuthorName() {
        return authorName;
    }

    public void setAuthorName(String authorName) {
        this.authorName = authorName;
    }

    public long getLastModifiedTimeStamp() {
        return lastModifiedTimeStamp;
    }

    public void setLastModifiedTimeStamp(long lastModifiedTimeStamp) {
        this.lastModifiedTimeStamp = lastModifiedTimeStamp;
    }

    public float getRating() {
        return rating;
    }

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

    public int getDownloads() {
        return downloads;
    }

    public void setDownloads(int downloads) {
        this.downloads = downloads;
    }

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

        Book that = (Book) o;

        if (downloads != that.downloads)
            return false;
        if (name != null ? !name.equals(that.name) :
                that.name != null) {
            return false;
        }
        return authorName != null ?
                authorName.equals(that.authorName) :
                that.authorName == null;

    }

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

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + authorName + '\'' +
                ", lastModifiedTimestamp='" + lastModifiedTimeStamp + '\'' +
                ", rating='" + rating + '\'' +
                ", downloads=" + downloads +
                '}';
    }
}

WOAH! That’s 96 lines of code for just storing 5 fields in an object. We aren’t doing much here besides having getter setters, toString(), equals() and hashCode() methods.

With the clean architectures and separation of code practices in our practices, we need to create POJO classes since every project needs to store data somewhere. This can increase the boilerplate code.

This is where Kotlin comes to the rescue, with the use of Data Classes.

Data Classes is Kotlin’s answer to reducing boilerplate code.

The above POJO class can be written in Kotlin in the following way:


data class Book(var name: String, var authorName: String, var lastModified: Long, var rating: Float, var downloads: Int)

THAT’S IT. Kotlin converts a 96 line java code to a single line of code.

This is Kotlin’s way of reducing the boilerplate code in your project!

Creating Kotlin Data Class

Following are the requirements for creating Kotlin Data class.

  • You need to append the class with the keyword data
  • The primary constructor needs to have at least one parameter.
  • Each parameter of the primary constructor must have a val or a var assigned.
    This isn’t the case with a normal class, where specifying a val or a var isn’t compulsory.
  • Data classes cannot be appended with abstract, open, sealed or inner

Kotlin Data Class built-in methods

Kotlin Data class automatically creates the following functions for you.

  • equals() and hashCode()
  • toString() of the form "Book(name=JournalDev, authorName=Anupam)"
  • componentN() functions for each of the parameters in the order specified. This is known as destructuring declarations.
  • copy()

Kotlin Data Class Features

Following are some features that a Data Class provides.

  • To create a parameterless constructor, specify default values to each of the parameters present in the primary constructor.
  • A Data Class allows subclassing(No need to mention the keyword open).
  • You can provide explicit implementations for the functions equals() hashCode() and toString()
  • Explicit implementations for copy() and componentN() functions are not allowed.
  • We can control the visibility of the getters and setters by specifying the visibility modifiers in the constructor as shown below.
    
    data class Book(var name: String,private var authorName: String, var lastModified: Long, var rating: Float, var downloads: Int)
    
  • A val parameter won’t have a setter defined implicitly(can’t be done explicitly too!).

Default And Named Arguments in Data Class

Following is our data class:


data class Book(var name: String, var authorName: String, var lastModified: Long, var rating: Float, var downloads: Int)

None of the parameters have a default value set. So we need to set an argument for each of them in the instantiation as shown below.


fun main(args: Array<String>) {
val book = Book("Android Tutorials","Anupam", 1234567, 4.5f, 1000)
}

Let’s set a few default arguments and see how the instantiation changes.



data class Book(var name: String, var authorName: String = "Anupam", var lastModified: Long = 1234567, var rating: Float = 5f, var downloads: Int = 1000)
fun main(args: Array<String>) {
var book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)

    book = Book("Kotlin")
    book = Book("Swift",downloads = 500)
    book = Book("Java","Pankaj",rating = 5f, downloads = 1000)
    book = Book("Python","Shubham",rating = 5f)

}

Instead of setting each argument, we can set only the non-default ones and the ones which we wish too using the named argument.
Using Named Arguments, we can set the 5th argument as the second one by explicitly specifying the parameter name followed by =. Life is so easier this way!

Kotlin Data Class toString() Method

The toString() is implicitly created and prints the argument names and labels for the instance as shown below.


data class Book(var name: String, var authorName: String = "Anupam", var lastModified: Long = 1234567, var rating: Float = 5f, var downloads: Int = 1000)


fun main(args: Array<String>) {

    var book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    println(book)
    book = Book("Kotlin")
    println(book)
    book = Book("Swift",downloads = 500)
    println(book)
    book = Book("Java","Pankaj",rating = 5f, downloads = 1000)
    println(book.toString())
    book = Book("Python","Shubham",rating = 5f)
    println(book.toString())


}

//Following is printed in the console.
//Book(name=Android tutorials, authorName=Anupam, lastModified=1234567, rating=4.5, downloads=1000)
//Book(name=Kotlin, authorName=Anupam, lastModified=1234567, rating=5.0, downloads=1000)
//Book(name=Swift, authorName=Anupam, lastModified=1234567, rating=5.0, downloads=500)
//Book(name=Java, authorName=Pankaj, lastModified=1234567, rating=5.0, downloads=1000)
//Book(name=Python, authorName=Shubham, lastModified=1234567, rating=5.0, downloads=1000)

Note: print function implicitly adds a toString().

Kotlin Data Class copy() Method

Copy function is used to create a copy of an instance of the data class with few of the properties modified.

It’s recommended to use val parameters in a data classes constructor in order to use immutable properties of an instances. Immutable objects are easier while working with multi-threaded applications.

Hence to create a copy of a immutable object by changing only few of the properties, copy() function is handy.


data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    println(book)

    val newBook = book.copy(name = "Kotlin")
    println(newBook)
}
//Following is printed in the console.
//Book(name=Android tutorials, authorName=Anupam, lastModified=1234567, rating=4.5, downloads=1000)
//Book(name=Kotlin, authorName=Anupam, lastModified=1234567, rating=4.5, downloads=1000)

Kotlin Data Class equals() and hashCode()

The hashCode() method returns hash code for the object. If two objects are equal, hashCode() produces the same integer result. Hence, equals() returns true if the hashCode() is equal, else it returns a false.


data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    println("Hashcode is ${book.hashCode()}")

    val newBook = book.copy(name = "Kotlin")
    println("Hashcode is ${newBook.hashCode()}")

    val copyBook = book.copy()
    println("Hashcode is ${copyBook.hashCode()}")


    if(copyBook.equals(book))
        println("copyBook and book are equal")

    if(!book.equals(newBook))
        println("newBook and book are NOT equal")

}

//Following is printed in the console.
//Hashcode is 649213087
//Hashcode is 1237165820
//Hashcode is 649213087
//copyBook and book are equal
//newBook and book are NOT equal

The first and third object hashcodes are equal hence they are equal.

Note: The equals() method is equivalent to == in kotlin.

Destructuring Declarations

componentN() function lets us access each of the arguments specified in the constructor, in the order specified. N is the number of parameters in the constructor.

kotlin data classes component functions


data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)

    println(book.component1()) //Android tutorials
    println(book.component2()) //Anupam
    println(book.component3()) //1234567
    println(book.component4()) //4.5
    println(book.component5()) //1000
    
}

Destructuring declarations allows us to access the arguments as properties from the class object as shown below.


data class Book(val name: String, val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    val (n,a,date,rating,downloads) = book
}

Note: If a visibility modifier such as private is set on any of the arguments, it can’t be accessed in the above function.


data class Book(val name: String,private val authorName: String = "Anupam", val lastModified: Long = 1234567, val rating: Float = 5f, val downloads: Int = 1000)

fun main(args: Array<String>) {

    val book = Book("Android tutorials","Anupam", 1234567, 4.5f, 1000)
    val (n,a,date,rating,downloads) = book //This won't compile since authorName is private
}

That’s all for quick roundup on Kotlin Data Classes.

References: Kotlin Docs

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages