Home / Programming / Kotlin / Kotlin Data Classes

Kotlin Data Classes

In this tutorial we are going to discuss kotlin data classes, and show some examples on how you can use them in your app.

We frequently create classes whose main purpose is to hold data. In such a case some standard functionality and utility functions are often mechanically derivable from the data. In Kotlin, this is called a data class and is marked as data

The compiler automatically derives the following members from all properties declared in the primary constructor:

  • equals()hashCode() pair;
  • toString() of the form "User(name=John, age=42)";
  • componentN()functions corresponding to the properties in their order of declaration;
  • copy()function (see below).

For Example, we might have a class such as Book.

class Book (val title: String, val publicationYear: String, val author: String, var price: Double){
}

let’s say in our app we don’t want the Book to do much we just want it to hold data. We just use it to store and then access the information. This is one of the cases where it’s better to use Data Class.

How do we Create Data Class?

by using the data keyword

data class DataBook (val title: String, val publicationYear: String, val author: String, var price: Double){
}

Data classes do a lot work for us and we do not need to implement anything for it to work

How do data classes work?

class Example {
 fun main(args: Array<String>) {
 val book = Book("Awesome Coding Book", "2018", "Edge Developer",49.99)
 println(book) // code.kotlin$Book@6f2c7a5e
 val databook = DataBook("Awesome Coding Book", "2018", "Edge Developer",49.99)
 println(databook) // DataBook(title=Awesome Coding Book, publicationYear=2018, author=Edge Developer, price=49.99)
 }
}
class Book (val title: String, val publicationYear: String, val author: String, var price : Double){
}
data class DataBook(val title: String, val publicationYear: String, val author: String, var price : Double) {
}

when we printed the Book object, it printed the packageName$Book@memoryAddress (which is not really useful) but DataBook (our data class) object correctly printed all the properties of the object.

We can also replicate what happened in the data class in the ordinary class but it will require extra code –overriding toString() method and specifying the result we wanted instead of the default packageName$Book@memoryAddress. Example is shown below.

class Example {
    fun main(args: Array<String>) {
        val book = Book("Awesome Coding Book", "2018", "Edge Developer",49.99)
        println(book) // Book[title=Awesome Coding Book, publicationYear=2018, author=Edge Developer, price=49.99]
        val databook = DataBook("Awesome Coding Book", "2018", "Edge Developer",49.99)
        println(databook) // DataBook(title=Awesome Coding Book, publicationYear=2018, author=Edge Developer, price=49.99)
    }
}
class Book (val title: String, val publicationYear: String, val author: String, var price : Double){
    override fun toString(): String {
        return "Book[title='$title', publicationYear='$publicationYear', author='$author', price=$price]"
    }
}
data class DataBook(val title: String, val publicationYear: String, val author: String, var price : Double) {
}

but in data classes overriding toString() method is unnecessary even though it’s possible.

Data Classes allow us to Compare objects much more usefully.

let’s say we have two DataBook (our data class) objects which are basically the same (have the exact same properties). we can compare them to see if they’re the same, which will will return true (they have same properties) but Book (ordinary class) object will return false (because it does not check equality of the properties) as shown below.

class Example {
    fun main(args: Array<String>) {
        val book = Book("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val book1 = Book("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val databook = DataBook("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val databook1 = DataBook("Awesome Coding Book", "2018", "Edge Developer",49.99)
        println(databook.equals(databook1)) // true
        println(book.equals(book1)) // false
    }
}
class Book (val title: String, val publicationYear: String, val author: String, var price : Double){
}
data class DataBook(val title: String, val publicationYear: String, val author: String, var price : Double) {
}

the reason the DataBook object with the same properties return true when compared to each other, is because under the hood kotlin compares individual properties of the object to another and found them to be the same hence return true. This is not the case for Book object.

to replicate this (comparison behavior) in the Book class we need to write extra code, as shown below

class Example {
    fun main(args: Array<String>) {
        val book = Book("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val book1 = Book("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val databook = DataBook("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val databook1 = DataBook("Awesome Coding Book", "2018", "Edge Developer",49.99)
        println(databook.equals(databook1)) // true
        println(book.equals(book1)) // true
    }
}
class Book (val title: String, val publicationYear: String, val author: String, var price : Double){
    override fun equals(other: Any?): Boolean {
        return toString().equals(other.toString())
    }
    override fun toString(): String {
        return "Book(title='$title', publicationYear='$publicationYear', author='$author', price=$price)"
    }

}
data class DataBook(val title: String, val publicationYear: String, val author: String, var price : Double) {
}

The Data Class and the use of copy() function

class Example {
    fun main(args: Array<String>) {
        val databook1 = DataBook("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val databook2 = databook1.copy(price = 29.99) 
// we copied remaining data but changed it's price
        print(databook2) 
//DataBook(title=Awesome Coding Book, publicationYear=2018, author=Edge Developer, price=29.99)
        val databook3 = databook1.copy()
// the above line will copy everything from databook1
        print(databook3) 
//DataBook(title=Awesome Coding Book, publicationYear=2018, author=Edge Developer, price=49.99)
    }
}
class Book (val title: String, val publicationYear: String, val author: String, var price : Double){
    override fun equals(other: Any?): Boolean {
        return toString().equals(other.toString())
    }
    override fun toString(): String {
        return "Book(title='$title', publicationYear='$publicationYear', author='$author', price=$price)"
    }

}
data class DataBook(val title: String, val publicationYear: String, val author: String, var price : Double) {
}

Decompose each objects into their properties

class Example {
    fun main(args: Array<String>) {
        val databook1 = DataBook("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val databook2 = databook1.copy(price = 29.99)
        var (title, pubYear, author, price) = databook2 //decomposing
        print("Title-> $title, Publication Year-> $pubYear, Author-> $author, Price-> $price")
//Title-> Awesome Coding Book, Publication Year-> 2018, Author-> Edge Developer, Price-> 29.99
    }
}
class Book (val title: String, val publicationYear: String, val author: String, var price : Double){
   override fun equals(other: Any?): Boolean {
   return toString().equals(other.toString())
}
override fun toString(): String {
  return "Book(title='$title', publicationYear='$publicationYear', author='$author', price=$price)"
}

}
data class DataBook(val title: String, val publicationYear: String, val author: String, var price : Double) {
}

Data classes and HashSets

from maths we know that a set cannot contain two elements of the same type.

class Example {
    fun main(args: Array<String>) {
        val book = Book("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val book1 = Book("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val databook = DataBook("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val databook1 = DataBook("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val databook2 = databook1.copy(price = 29.99)
        val setONE = hashSetOf(databook, databook1, databook2)
        println(setONE)
        val setTWO = hashSetOf(book, book1)
        println(setTWO)

    }
}
class Book (val title: String, val publicationYear: String, val author: String, var price : Double){
    override fun equals(other: Any?): Boolean {
        return toString().equals(other.toString())
    }
    override fun toString(): String {
        return "Book(title='$title', publicationYear='$publicationYear', author='$author', price=$price)"
    }
}
data class DataBook(val title: String, val publicationYear: String, val author: String, var price : Double) {
}

println(setONE) printed the following to the console [DataBook(title=Awesome Coding Book, publicationYear=2018, author=Edge Developer, price=49.99), DataBook(title=Awesome Coding Book, publicationYear=2018, author=Edge Developer, price=29.99)] as you can see only two DataBook object was stored in the hashset even though we supplied 3 (one was a copy, 2 original 1 copy). Using hash set on Data Class object will automatically eliminate duplicates without further code.

while

println(setTWO) printed the following to the console [Book(title='Awesome Coding Book', publicationYear='2018', author='Edge Developer', price=49.99), Book(title='Awesome Coding Book', publicationYear='2018', author='Edge Developer', price=49.99)] . From the printed result setTWO hashset did not eliminate the duplicates even though a set is not supposed to contain any duplicates

Data classes do a lot of work for us, they are very useful feature.

Lastly, we can write any method within our data classes

class Example {
    fun main(args: Array<String>) {
        val book = Book("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val book1 = Book("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val databook = DataBook("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val databook1 = DataBook("Awesome Coding Book", "2018", "Edge Developer",49.99)
        val databook2 = databook1.copy(price = 29.99)
        println("Book Hash Code ${book.hashCode()}")

        val setONE = hashSetOf(databook, databook1, databook2)
        println(setONE)
        val setTWO = hashSetOf(book, book1)
        println(setTWO)
        databook1.doSomething() // "Doing Something..."

    }
}
class Book (val title: String, val publicationYear: String, val author: String, var price : Double){
    override fun equals(other: Any?): Boolean {
        return toString().equals(other.toString())
    }
    override fun toString(): String {
        return "Book(title='$title', publicationYear='$publicationYear', author='$author', price=$price)"
    }
}
data class DataBook(val title: String, val publicationYear: String, val author: String, var price : Double) {
    fun doSomething(){
        print("Doing Something...")
    }
}

Data classes cannot be declared abstract therefore cannot have any abstract function within it.

You can read more about data classes from it’s official documentation 

You can also use the official kotlin compiler to test your code ONLINE

About Edge Developer

Hello there, my name is Opeyemi Olorunleke. I am a Software Developer (majorly Android, GitHub Profile), Digital Marketer, Udemy Instructor, Technical Writer, Blogger & Webmaster.

Check Also

RecyclerView Multi-Select using KOTLIN

Implementing multi-select on a Recycler View can be tricky and complicated. However, by the end …

Leave a Reply

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