Menu
Coddy logo textTech

Data Classes

Part of the Object Oriented Programming section of Coddy's Kotlin journey. Lesson 32 of 57.

A data class is a class whose main job is to hold data. The data modifier makes the compiler generate toString(), equals(), hashCode(), copy() and componentN() from the properties of the primary constructor:

data class Point(val x: Int, val y: Int)

Inside main:

val a = Point(1, 2)
val b = Point(1, 2)
println(a)
println(a == b)
println(setOf(a, b).size)

Output:

Point(x=1, y=2)
true
1

Without data, println shows the class name and a hash code such as Point@1b6d3586, and two objects with the same values are not equal. copy() creates a new object with some properties changed and leaves the original as it is, so a data class with val properties works as an immutable value:

data class User(val name: String, val email: String, val admin: Boolean = false)

Inside main:

val ada = User("Ada", "ada@example.com")
val boss = ada.copy(admin = true)
println(ada)
println(boss)
println(ada == boss)

Output:

User(name=Ada, email=ada@example.com, admin=false)
User(name=Ada, email=ada@example.com, admin=true)
false

Destructuring declarations unpack an object into variables: val (x, y) = point calls the generated component1() and component2(), in the order of the constructor. It also works in for loops and lambda parameters, and _ skips a property:

data class Score(val player: String, val points: Int, val level: Int)

Inside main:

val scores = listOf(Score("ada", 120, 3), Score("bo", 95, 2))
for ((player, points) in scores) println("$player: $points")
val (_, bestPoints, bestLevel) = scores.maxBy { it.points }
println("best: $bestPoints at level $bestLevel")

Output:

ada: 120
bo: 95
best: 120 at level 3

Only primary-constructor properties take part: a property declared in the class body is left out of toString, equals, hashCode and copy. A data class needs at least one constructor parameter, and every parameter must be a val or var:

data class Reading(val sensor: String, val value: Int) {
    var note = ""
}

Inside main:

val r1 = Reading("t1", 20)
val r2 = Reading("t1", 20)
r1.note = "checked"
println(r1)
println(r1 == r2)

Output:

Reading(sensor=t1, value=20)
true
challenge icon

Challenge

Easy

Make Book a data class so it prints and compares by value. Then complete three functions: parse(line) turns Dune;Herbert;1965 into a Book, newEdition(book, year) returns a copy with the new year and (new edition) added to the title, and describe(book) returns Dune by Herbert, 1965 using a destructuring declaration.

The supplied code parses every input line, prints each book, the number of duplicates, the new edition of the first book (year 2024) and a description of every distinct book.

Your code goes in Book.kt and BookTools.kt. Main.kt holds the supplied input/output code and cannot be edited.

Try it yourself

fun main() {
    // Supplied input/output code: keep it as it is
    val input = generateSequence(::readLine).toList()
    val books = input.map { parse(it) }
    for (b in books) println(b)
    println("duplicates: ${books.size - books.distinct().size}")
    println(newEdition(books[0], 2024))
    for (b in books.distinct()) println(describe(b))
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming

Practice on your own: Kotlin playground