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
1Without 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)
falseDestructuring 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 3Only 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)
trueChallenge
EasyMake 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))
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Classes and Objects
Working With FilesDefining ClassesPrimary Constructorsinit Blocks and ValidationSecondary ConstructorsRecap - Library Card4Inheritance
Open Classes and SubclassesOverriding Memberssuper and ConstructorsAbstract ClassesRecap - Staff Directory7Special Classes
Data ClassesEnum ClassesSealed Hierarchiesequals, hashCode, toStringRecap - Order Tracker2Properties and Encapsulation
Custom AccessorsVisibility ModifiersPrivate Setterslazy and lateinitRecap - Bank Account5Interfaces
Declaring InterfacesDefault MethodsMultiple InterfacesInterfaces as TypesRecap - Payment Methods8Generics
Generic FunctionsGeneric ClassesType ConstraintsVariance With in and outRecap - Priority Queue11Project: Library Management
Books and MembersBorrowing BooksPractice on your own: Kotlin playground