Kotlin Data Class

In this article, you will learn to create data classes in Kotlin. You will also learn about requirements that data class must fulfill, and their standard functionalities.

There may arise a situation where you need to create a class solely to hold data. In such cases, you can mark the class as data to create a data class. For example,

data class Person(val name: String, var age: Int)

For this class, the compiler automatically generates:

  • copy() function, equals() and hashCode() pair, and toString() form of the primary constructor
  • componentN() functions

Before talking about these features in detail, let’s talk about requirements that a data class must fulfill.


Kotlin Data Class Requirements

Here are the requirements:

  • The primary constructor must have at least one parameter.
  • The parameters of the primary constructor must be marked as either val (read-only) or var (read-write).
  • The class cannot be open, abstract, inner or sealed.
  • The class may extend other classes or implement interfaces. If you are using Kotlin version before 1.1, the class can only implement interfaces.

Example: Kotlin Data Class

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

fun main(args: Array<String>) {
    val jack = User("jack", 29)
    println("name = ${jack.name}")
    println("age = ${jack.age}")
}

When you run the program, the output will be:

name = jack
age = 29

When you declare a data class, the compiler automatically generates several functions such as toString()equals()hashcode() etc behind the scenes. This helps to keep you code concise. Had you used Java, you would need to write a lot of boilerplate code.

Let’s use these functions:


Copying

For a data class, you can create a copy of an object with some of its properties different using copy() function. Here’s how it works:

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

fun main(args: Array<String>) {
    val u1 = User("John", 29)
   
    // using copy function to create an object
    val u2 = u1.copy(name = "Randy")

    println("u1: name = ${u1.name}, name = ${u1.age}")
    println("u2: name = ${u2.name}, name = ${u2.age}")
}

When you run the program, the output will be:

u1: name = John, name = 29
u2: name = Randy, name = 29

toString() method

The toString() function returns a string representation of the object.

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

fun main(args: Array<String>) {
    val u1 = User("John", 29)
    println(u1.toString())
}

When you run the program, the output will be:

User(name=John, age=29)

hashCode() and equals()

The hasCode() method returns hash code for the object. If two objects are equal, hashCode() produces the same integer result.

The equals() returns true if two objects are equal (has same hashCode()). If objects are not equal, equals() returns false

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

fun main(args: Array<String>) {
    val u1 = User("John", 29)
    val u2 = u1.copy()
    val u3 = u1.copy(name = "Amanda")

    println("u1 hashcode = ${u1.hashCode()}")
    println("u2 hashcode = ${u2.hashCode()}")
    println("u3 hashcode = ${u3.hashCode()}")

    if (u1.equals(u2) == true)
        println("u1 is equal to u2.")
    else
        println("u1 is not equal to u2.")

    if (u1.equals(u3) == true)
        println("u1 is equal to u3.")
    else
        println("u1 is not equal to u3.")
}

When you run the program, the output will be:

u1 hashcode = 71750738
u2 hashcode = 71750738
u3 hashcode = 771732263
u1 is equal to u2.
u1 is not equal to u3.

Destructuring Declarations

You can destructure an object into a number of variables using destructing declaration. For example:

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

fun main(args: Array<String>) {
    val u1 = User("John", 29, "Male")

    val (name, age, gender) = u1
    println("name = $name")
    println("age = $age")
    println("gender = $gender")
}

When you run the program, the output will be:

name = John
age = 29
gender = Male

This was possible because the compiler generates componentN() functions all properties for a data class. For example:

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

fun main(args: Array<String>) {
    val u1 = User("John", 29, "Male")

    println(u1.component1())     // John
    println(u1.component2())     // 29  
    println(u1.component3())     // "Male"
}

When you run the program, the output will be:

John
29
Male

Kotlin Getters and Setters

In this article, you will learn to use getters and setters in Kotlin with the help of an example.

Before you learn about getters and setter, be sure to check Kotlin class and objects.

In programming, getters are used for getting value of the property. Similarly, setters are used for setting value of the property.

In Kotlin, getters and setters are optional and are auto-generated if you do not create them in your program.


How getters and setters work?

The following code in Kotlin

class Person {
    var name: String = "defaultValue"
}

is equivalent to

class Person {
    var name: String = "defaultValue"

    // getter
    get() = field

    // setter
    set(value) {
        field = value
    }
}

When you instantiate object of the Person class and initialize the name property, it is passed to the setters parameter value and sets field to value.

val p = Person()
p.name = "jack"

Now, when you access name property of the object, you will get field because of the code get() = field.

println("${p.name}")

Here’s an working example:

fun main(args: Array<String>) {

    val p = Person()
    p.name = "jack"
    println("${p.name}")
}

class Person {
    var name: String = "defaultValue"

    get() = field

    set(value) {
        field = value
    }
}

When you run the program, the output will be:

jack

This is how getters and setters work by default. However, you can change value of the property (modify value) using getters and setters.


Example: Changing value of the property

fun main(args: Array<String>) {

    val maria = Girl()
    maria.actualAge = 15
    maria.age = 15
    println("Maria: actual age = ${maria.actualAge}")
    println("Maria: pretended age = ${maria.age}")

    val angela = Girl()
    angela.actualAge = 35
    angela.age = 35
    println("Angela: actual age = ${angela.actualAge}")
    println("Angela: pretended age = ${angela.age}")
}

class Girl {
    var age: Int = 0
    get() = field
    set(value) {
        field = if (value < 18)
            18
        else if (value >= 18 && value <= 30)
            value
        else
            value-3
    }

    var actualAge: Int = 0
}

When you run the program, the output will be:

Maria: actual age = 15
Maria: pretended age = 18
Angela: actual age = 35
Angela: pretended age = 32

Here, the actualAge property works as expected.

However, there is additional logic is setters to modify value of the age property.

Kotlin Class and Objects

In this article, you’ll be introduced to Object-oriented programming in Kotlin. You’ll learn what a class is, how to create objects and use it in your program.

Kotlin supports both functional and object-oriented programming.

Kotlin supports features such as higher-order functionsfunction types and lambdas which makes it a great choice for working in functional programming style. You will learn about these concept in later chapters. This article will focus on object-oriented style of programming in Kotlin.


Object-oriented Programming (OOP)

In object-oriented style of programming, you can divide a complex problem into smaller sets by creating objects.

These objects share two characteristics:

  • state
  • behavior

Let’s take few examples:

  1. Lamp is an object
    • It can be in on or off state.
    • You can turn on and turn off lamp (behavior).
  2. Bicycle is an object
    • It has current geartwo wheelsnumber of gear etc. states.
    • It has brakingacceleratingchanging gears etc. behavior.

You will learn about detail features of an object-oriented programming like: data encapsulationinheritance and polymorphism as we go on. This article will focus on the basics to keep things simple.


Kotlin Class

Before you create objects in Kotlin, you need to define a class.

A class is a blueprint for the object.

We can think of class as a sketch (prototype) of a house. It contains all the details about the floors, doors, windows etc. Based on these descriptions we build the house. House is the object.

Since, many houses can be made from the same description, we can create many objects from a class.


How to define a class in Kotlin?

To define a class in Kotlin, class keyword is used:

class ClassName {
    // property
    // member function
    ... .. ...
}

Here’s an example:

class Lamp {

    // property (data member)
    private var isOn: Boolean = false

    // member function
    fun turnOn() {
        isOn = true
    }

    // member function
    fun turnOff() {
        isOn = false
    }
}

Here, we defined a class named Lamp.

The class has one property isOn (defined in same way as variable), and two member functions turnOn() and turnOff().

In Kotlin, either the property must be initialized or must be declared abstract (Visit: Kotlin Abstract Class to learn more). In the above example, isOn property is initialized to false.


Classes, objects, properties, member function etc. can have visibility modifiers. For example, the isOn property is private. This means, the isOn property can be changed from only inside the Lamp class.

Other visibility modifiers are:

  • private – visible (can be accessed) from inside the class only.
  • public – visible everywhere.
  • protected – visible to the class and its subclass.
  • internal – any client inside the module can access them.

You will learn about protected and internal modifiers later in Kotlin visibility modifiers article.

If you do not specify the visibility modifier, it will be public by default.

In the above program, turnOn() and turnOff() member functions are public whereas, isOn property is private.


Kotlin Objects

When class is defined, only the specification for the object is defined; no memory or storage is allocated.

To access members defined within the class, you need to create objects. Let’s create objects of Lamp class.

class Lamp {

    // property (data member)
    private var isOn: Boolean = false

    // member function
    fun turnOn() {
        isOn = true
    }

    // member function
    fun turnOff() {
        isOn = false
    }
}

fun main(args: Array<String>) {

    val l1 = Lamp() // create l1 object of Lamp class
    val l2 = Lamp() // create l2 object of Lamp class
}

This program creates two objects l1 and l2 of class Lamp. The isOn property for both lamps l1 and l2 will be false.


How to access members?

You can access properties and member functions of a class by using . notation. For example,

l1.turnOn()

This statement calls turnOn() function for l1 object.

Let’s take another example:

l2.isOn = true

Here, we tried to assign true to isOn property of l2 object. Note that, isOn property is private, and if you try to access isOn from outside the class, an exception is thrown.


Example: Kotlin Class and Object

class Lamp {

    // property (data member)
    private var isOn: Boolean = false

    // member function
    fun turnOn() {
        isOn = true
    }

    // member function
    fun turnOff() {
        isOn = false
    }

    fun displayLightStatus(lamp: String) {
        if (isOn == true)
            println("$lamp lamp is on.")
        else
            println("$lamp lamp is off.")
    }
}

fun main(args: Array<String>) {

    val l1 = Lamp() // create l1 object of Lamp class
    val l2 = Lamp() // create l2 object of Lamp class

    l1.turnOn()
    l2.turnOff()

    l1.displayLightStatus("l1")
    l2.displayLightStatus("l2")
}

When you run the program, the output will be:

l1 Lamp is on.
l2 Lamp is off.

In the above program,

  • Lamp class is created.
  • The class has a property isOn and three member functions turnOn()turnOff() and displayLightStatus().
  • Two objects l1 and l2 of Lamp class are created in the main() function.
  • Here, turnOn() function is called using l1 object: l1.turnOn(). This method sets isOn instance variable of l1 object to true.
  • And, turnOff() function is called using l2 object: l1.turnOff(). This method sets isOff instance variable of l2 object to false.
  • Then, displayLightStatus() function is called for l1 and l2 objects which prints appropriate message depending on whether isOn property is true or false.

Notice that, the isOn property is initialized to false inside the class. When an object of the class is created, isOn property for the object is initialized to false automatically. So, it’s not necessary for l2 object to call turnOff() to set isOn property to false.

For example:

class Lamp {

    // property (data member)
    private var isOn: Boolean = false

    // member function
    fun turnOn() {
        isOn = true
    }

    // member function
    fun turnOff() {
        isOn = false
    }

    fun displayLightStatus() {
        if (isOn == true)
            println("lamp is on.")
        else
            println("lamp is off.")
    }
}

fun main(args: Array<String>) {

    val lamp = Lamp()
    lamp.displayLightStatus()
}

When you run the program, the output will be:

lamp is off.

Kotlin for Loop

The for loop in Kotlin iterates through anything that provides an iterator. In this article, you learn to create for loop (with the help of examples).

There is no traditional for loop in Kotlin unlike Java and other languages.

In Kotlin, for loop is used to iterate through ranges, arrays, maps and so on (anything that provides an iterator).

The syntax of for loop in Kotlin is:

for (item in collection) {
    // body of loop
}

Example: Iterate Through a Range

fun main(args: Array<String>) {

    for (i in 1..5) {
        println(i)
    }
}

Here, the loop iterates through the range and prints individual item.

When you run the program, the output will be:

1
2
3
4
5

If the body of the loop contains only one statement (like above example), it’s not necessary to use curly braces { }.

fun main(args: Array<String>) {
    for (i in 1..5) println(i)
}

It’s possible to iterate through a range using for loop because ranges provides an iterator. To learn more, visit Kotlin iterators.


Example: Different Ways to Iterate Through a Range

fun main(args: Array<String>) {

    print("for (i in 1..5) print(i) = ")
    for (i in 1..5) print(i)

    println()

    print("for (i in 5..1) print(i) = ")
    for (i in 5..1) print(i)             // prints nothing

    println()

    print("for (i in 5 downTo 1) print(i) = ")
    for (i in 5 downTo 1) print(i)

    println()

    print("for (i in 1..4 step 2) print(i) = ")
    for (i in 1..5 step 2) print(i)

    println()

    print("for (i in 4 downTo 1 step 2) print(i) = ")
    for (i in 5 downTo 1 step 2) print(i)
}

When you run the program, the output will be:

for (i in 1..5) print(i) = 12345
for (i in 5..1) print(i) = 
for (i in 5 downTo 1) print(i) = 54321
for (i in 1..4 step 2) print(i) = 135
for (i in 4 downTo 1 step 2) print(i) = 531

Iterating Through an Array

Here’s an example to iterate through a String array.

fun main(args: Array<String>) {

    var language = arrayOf("Ruby", "Koltin", "Python" "Java")

    for (item in language)
        println(item)
}

When you run the program, the output will be:

Ruby
Koltin
Python
Java

It’s possible to iterate through an array with an index. For example,

fun main(args: Array<String>) {

    var language = arrayOf("Ruby", "Koltin", "Python", "Java")

    for (item in language.indices) {

        // printing array elements having even index only
        if (item%2 == 0)
            println(language[item])
    }
}

When you run the program, the output will be:

Ruby
Python

If you want to learn more about arrays, visit Kotlin arrays.


Iterating Through a String

fun main(args: Array<String>) {

    var text= "Kotlin"

    for (letter in text) {
        println(letter)
    }
}

When you run the program, the output will be:

K
o
t
l
i
n

Similar like arrays, you can iterate through a String with an index. For example,

fun main(args: Array<String>) {

    var text= "Kotlin"

    for (item in text.indices) {
        println(text[item])
    }
}

When you run the program, the output will be:

K
o
t
l
i
n

You will learn to iterate over a map using for loop in Kotin map article.