Kotlin Data Class — What It Is & How to Use It
A quick, job-ready guide with examples and best practices.
What is a Data Class?
A data class in Kotlin is a concise way to create a class that is primarily used to hold data. When you
mark a class with the data keyword, the compiler automatically generates common utility functions like
equals(), hashCode(), toString(), copy(), and componentN() functions for destructuring.
Minimum Requirements
• Must have a primary constructor with at least one parameter.
• Primary constructor parameters must be marked val or var to become properties.
• Data classes cannot be abstract, open, sealed, or inner.
• They can implement interfaces, but cannot extend other classes (besides Any).
Basic Example
data class User(
val id: Long,
val name: String,
val email: String
)
fun main() {
val u1 = User(1L, "Asha", "asha@example.com")
val u2 = User(1L, "Asha", "asha@example.com")
println(u1) // toString(): User(id=1, name=Asha, email=asha@example.com)
println(u1 == u2) // true (structural equality via equals)
val u3 = u1.copy(name = "Asha K.") // copy with modified property
println(u3)
val (id, name, email) = u3 // destructuring via componentN()
println("$id, $name, $email")
}
Why Use Data Classes?
• Less boilerplate: auto-generated equals/hashCode/toString/copy.
• Safer equality: structural equality by default for logical comparison.
• Immutability-friendly: model state as immutable (prefer val props).
• Great for collections: behave correctly in sets/maps due to proper hashCode.
• Destructuring: easy unpacking of values for readability.
Common Use-Cases
• DTOs / API models: parse JSON responses and send requests (with libraries like
Retrofit/Moshi/Kotlinx Serialization).
• Database entities: Room/Realm models (with the required annotations).
• UI state in Jetpack Compose: represent immutable state and use copy() to create new versions.
• Domain models and value objects in clean architecture.
• Keys in maps/sets where logical equality matters.
Copy + Immutability Pattern (Recommended)
data class CounterState(val count: Int = 0)
fun inc(state: CounterState): CounterState = state.copy(count = state.count + 1)
fun main() {
var state = CounterState() // CounterState(count=0)
state = inc(state) // CounterState(count=1)
println(state)
}
Destructuring in Loops/Collections
data class Point(val x: Int, val y: Int)
fun main() {
val points = listOf(Point(1, 2), Point(3, 4))
for ((x, y) in points) {
println("x=$x y=$y")
}
}
equals(), hashCode(), and toString()
For data classes, equals() and hashCode() are generated using all properties declared in the primary
constructor. Properties declared only in the class body are not included. This ensures reliable behavior
in collection types like HashSet and HashMap. toString() prints a concise representation for
debugging/logging.
Advanced Tips & Pitfalls
• Prefer val properties for immutability; use copy() to evolve state.
• Avoid putting mutable collections (MutableList, MutableMap) as properties. If needed, expose them as
read-only (List/Map) or make defensive copies.
• Do not rely on property order for equality—it's based on names/values in the primary constructor.
• If you override equals() or hashCode(), keep them consistent to avoid collection bugs.
• Use default values in the primary constructor for optional fields and convenient copy() calls.
Example: Default Args + Serialization
import kotlinx.serialization.Serializable
@Serializable
data class Todo(
val id: String,
val title: String,
val done: Boolean = false,
val tags: List<String> = emptyList()
)
When NOT to Use a Data Class
• When identity or behavior is more important than stored data (rich domain models with many
methods).
• When you need inheritance: data classes cannot be abstract/open/sealed/inner.
• When you need mutable, long-lived objects with complex invariants—use regular classes instead.
Summary
Use data class to represent immutable data with minimal boilerplate. You get correct equality, hashing,
readable toString(), copy() for safe updates, and destructuring support—all generated by the compiler.