Data classes

Kotlin · Essentials · 10 min

Data classes are the idiomatic way to model DTOs, API payloads and value objects in one line.

Mark a class data and the compiler generates the boilerplate from the properties in its primary constructor:

data class User(val name: String, val age: Int)
  • equals / hashCode compare property values, so two User("Ada", 36) are equal and work as map keys or in sets.
  • toString gives User(name=Ada, age=36).
  • copy(age = 37) creates a modified copy, leaving the original untouched: the idiomatic way to "change" immutable data.
  • component1(), component2() enable destructuring: val (name, age) = user.

Requirements: the primary constructor needs at least one val/var parameter, and data classes can't be open or abstract. Only properties in the primary constructor take part in equality and toString; properties declared in the body are ignored.

Use val properties to keep instances immutable; copy is shallow, so a MutableList inside is shared between copies.

Destructuring also works in loops and lambdas: for ((k, v) in map), pairs.map { (a, b) -> a + b }. Use _ for unused components.

Kotlin's standard Pair and Triple are data classes too, but a named data class almost always reads better. For single-value wrappers without allocation overhead, see value classes (Advanced).

Example

data class User(val name: String, val age: Int, val tags: List<String> = emptyList())

fun main() {
    val a = User("Ada", 36)
    val b = User("Ada", 36)
    println(a == b)              // true  (structural equality)
    println(a === b)             // false (different objects)
    println(a)                   // User(name=Ada, age=36, tags=[])

    val older = a.copy(age = 37)
    println("${a.age} ${older.age}") // 36 37

    val (name, age) = older
    println("$name is $age")     // Ada is 37

    val users = setOf(a, b, older)
    println(users.size)          // 2

    val pairs = listOf(User("Bo", 20), User("Cy", 30))
    println(pairs.map { (n, _) -> n.lowercase() }) // [bo, cy]
}

Remember

  • data generates equals, hashCode, toString, copy and componentN
  • Only primary constructor properties count
  • copy(...) makes modified shallow copies
  • Destructure with val (a, b) = obj

Watch out for

  • Declaring a property in the class body and expecting it to be part of equals.

Check yourself

  1. For data class P(val x: Int) { var note = "" }, are P(1).apply { note = "a" } and P(1) equal?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: kotlinlang.org/docs/data-classes.html