In this section, we will explore two powerful features of Kotlin: Data Classes and Sealed Classes. These features help in creating more readable, maintainable, and concise code.

Data Classes

Data classes are a concise way to create classes that are primarily used to hold data. Kotlin provides a special syntax for data classes that automatically generates useful methods such as equals(), hashCode(), toString(), and copy().

Key Features of Data Classes

  1. Primary Constructor: Must have at least one parameter.
  2. Properties: Parameters in the primary constructor are automatically properties.
  3. Generated Methods: equals(), hashCode(), toString(), copy(), and componentN() functions.

Example

data class User(val name: String, val age: Int)

fun main() {
    val user1 = User("Alice", 30)
    val user2 = User("Bob", 25)
    
    // toString() method
    println(user1) // Output: User(name=Alice, age=30)
    
    // equals() method
    println(user1 == User("Alice", 30)) // Output: true
    
    // copy() method
    val user3 = user1.copy(name = "Charlie")
    println(user3) // Output: User(name=Charlie, age=30)
}

Practical Exercise

Task: Create a data class Book with properties title, author, and year. Instantiate the class and use the generated methods.

Solution:

data class Book(val title: String, val author: String, val year: Int)

fun main() {
    val book1 = Book("1984", "George Orwell", 1949)
    val book2 = Book("Brave New World", "Aldous Huxley", 1932)
    
    // toString() method
    println(book1) // Output: Book(title=1984, author=George Orwell, year=1949)
    
    // equals() method
    println(book1 == Book("1984", "George Orwell", 1949)) // Output: true
    
    // copy() method
    val book3 = book1.copy(year = 2021)
    println(book3) // Output: Book(title=1984, author=George Orwell, year=2021)
}

Sealed Classes

Sealed classes are used to represent restricted class hierarchies. They allow you to define a closed set of subclasses, which makes it easier to handle different types of data in a type-safe manner.

Key Features of Sealed Classes

  1. Restricted Hierarchy: All subclasses must be defined within the same file.
  2. Exhaustive When Expressions: When expressions can be exhaustive, ensuring all cases are handled.

Example

sealed class Result {
    data class Success(val data: String) : Result()
    data class Error(val exception: Exception) : Result()
    object Loading : Result()
}

fun handleResult(result: Result) {
    when (result) {
        is Result.Success -> println("Success: ${result.data}")
        is Result.Error -> println("Error: ${result.exception.message}")
        Result.Loading -> println("Loading...")
    }
}

fun main() {
    val success = Result.Success("Data loaded successfully")
    val error = Result.Error(Exception("Network error"))
    val loading = Result.Loading
    
    handleResult(success) // Output: Success: Data loaded successfully
    handleResult(error)   // Output: Error: Network error
    handleResult(loading) // Output: Loading...
}

Practical Exercise

Task: Create a sealed class Response with subclasses Success, Failure, and Pending. Write a function to handle each type of response.

Solution:

sealed class Response {
    data class Success(val message: String) : Response()
    data class Failure(val error: String) : Response()
    object Pending : Response()
}

fun handleResponse(response: Response) {
    when (response) {
        is Response.Success -> println("Success: ${response.message}")
        is Response.Failure -> println("Failure: ${response.error}")
        Response.Pending -> println("Pending...")
    }
}

fun main() {
    val success = Response.Success("Operation completed successfully")
    val failure = Response.Failure("Operation failed")
    val pending = Response.Pending
    
    handleResponse(success) // Output: Success: Operation completed successfully
    handleResponse(failure) // Output: Failure: Operation failed
    handleResponse(pending) // Output: Pending...
}

Conclusion

In this section, we covered the basics of Data Classes and Sealed Classes in Kotlin. Data classes provide a concise way to create classes that primarily hold data, while sealed classes allow you to define a restricted class hierarchy, making it easier to handle different types of data in a type-safe manner. These features help in writing more readable and maintainable code. In the next section, we will explore Object Declarations and Companion Objects.

© Copyright 2024. All rights reserved