Share
Explore

Data Classes with Custom Methods in Kotlin

Data Classes with Custom Methods in Kotlin

Yes, Kotlin data classes can absolutely have custom methods!
Data classes are primarily designed to hold data, but they're still full-fledged classes and can include any functionality you'd put in a regular class.

By good design guidelines, these methods should be restricted to implementing BUSINESS LOGIC for those data fields only. Only methods related to doing business logic checks for setting and getting data field values.
Here's a complete working example showing different types of methods you can add to a data class:
/**
* Kotlin Data Class with Custom Methods Example
* This example demonstrates that data classes can contain various types of methods
* beyond the automatically generated ones.
*/

fun main() {
// Create a student
val student = Student("John", "Doe", 3.8)
// Use automatically generated toString()
println("Student (auto-generated toString): $student")
// Use a custom instance method
println("Student's full name: ${student.getFullName()}")
// Use a method that modifies the object and returns a new instance
val upperCaseStudent = student.withNamesUppercased()
println("Uppercase student: $upperCaseStudent")
// Use a static-like method from companion object
val honorsStudent = Student.createHonorsStudent("Alice", "Johnson")
println("Honors student: $honorsStudent")
println("Is honors student? ${honorsStudent.isHonorsStudent()}")
println("Is regular student honors? ${student.isHonorsStudent()}")
// Demonstrate the calculated property
println("Letter grade for ${student.getFullName()}: ${student.letterGrade}")
// Using an extension function on the data class
println("Student's email: ${student.generateEmail("university.edu")}")
// Compare two students (showing that equals still works)
val studentCopy = Student("John", "Doe", 3.8)
println("Are students equal? ${student == studentCopy}")
}

/**
* A data class representing a student with custom methods
*/
data class Student(val firstName: String, val lastName: String, val gpa: Double) {
// Custom instance method
fun getFullName(): String {
return "$firstName $lastName"
}
// Method that returns a new modified instance (preserving immutability)
fun withNamesUppercased(): Student {
return this.copy(
firstName = firstName.uppercase(),
lastName = lastName.uppercase()
)
}
// Method with logic
fun isHonorsStudent(): Boolean {
return gpa >= 3.5
}
// Custom property with a getter (calculated property)
val letterGrade: Char
get() = when {
gpa >= 4.0 -> 'A'
gpa >= 3.0 -> 'B'
gpa >= 2.0 -> 'C'
gpa >= 1.0 -> 'D'
else -> 'F'
}
// Companion object with "static" methods
companion object {
fun createHonorsStudent(firstName: String, lastName: String): Student {
return Student(firstName, lastName, 4.0)
}
// Factory method with validation
fun createWithValidation(firstName: String, lastName: String, gpa: Double): Student? {
if (firstName.isBlank() || lastName.isBlank() || gpa < 0 || gpa > 4.0) {
return null
}
return Student(firstName, lastName, gpa)
}
}
}

// Extension function on the data class
fun Student.generateEmail(domain: String): String {
return "${firstName.lowercase()}.${lastName.lowercase()}@$domain"
}

What Makes This Work

When you create a data class in Kotlin:
The compiler automatically generates
equals() and hashCode() based on all properties
A toString() method that shows all properties
componentN() functions for destructuring
A copy() method for creating modified copies
Beyond these basics, you can add:
Regular instance methods (like getFullName())
Methods that create modified instances (like withNamesUppercased())
Calculated properties with custom getters (like letterGrade)
Companion object with factory methods (like createHonorsStudent())
Extension functions (like generateEmail())

Important Considerations

Data classes are designed primarily for holding data, so adding too much behavior might indicate that a regular class would be more appropriate
The automatically generated methods only consider the properties in the primary constructor
Methods added to data classes don't affect equality comparisons unless they modify the properties
When adding custom setters to properties, be careful not to violate the expectation that equal inputs produce equal outputs
Data classes with custom methods give you the best of both worlds: the convenience of automatically generated methods for data handling and the flexibility to add custom behavior when needed.
Want to print your doc?
This is not the way.
Try clicking the ⋯ next to your doc name or using a keyboard shortcut (
CtrlP
) instead.