Learning Kotlin Constructor as a Java Developer

I have been developing Android apps in Java for years. I recently joined GameChanger and was excited to learn that GameChanger is using Kotlin. I originally thought that moving to Kotlin would be as simple as learning some new syntax, but I discovered that there was more to it. After a brief learning period, I’m […]

I have been developing Android apps in Java for years. I recently joined GameChanger and was excited to learn that GameChanger is using Kotlin. I originally thought that moving to Kotlin would be as simple as learning some new syntax, but I discovered that there was more to it. After a brief learning period, I’m up and running working in Kotlin. In this article, I’ll save you some of the trial-and-error by introducing some important concepts about constructors for those making the jump from Java to Kotlin.

Not All Constructors are Created Equal in Kotlin

In Java, all constructors are equal in a sense.

public class Person {

   String name;
   int age;

   public Person(Person p) {
       name = p.name;
       age = p.age;
   }

   public Person(String n, int a) {
       name = n;
       age = a;
   }
}

Take the above example, Person(Person p) and Person(String name, int age) can be used independently. Of course, you can choose to have one calling another, but it’s not required by the language.

In Kotlin there is always a primary constructor. Any additional constructors are secondary constructors. The primary constructor is always incorporated into the class header.

class Person(n: String, a: Int) {
   var name: String = n
   var age: Int = a
}

The variables name and age are initialized with n and a. In fact, n and a are available anywhere in the class for variable initialization.

class Person(n: String, a: Int) {
   var name: String = n
   var age: Int = a
   var nameX2: String = n + n

   init {
       println("The age is: " + a)
   }
}

Any other constructors would become secondary constructors which are required to call the primary constructor in the very beginning.

class Person(n: String, a: Int) {
   var name: String = n
   var age: Int = a

   constructor(p: Person) : this(p.name, p.age) { }
}

The Order of Creation

So, what is the order of processing when calling a secondary constructor? The primary constructor is invoked first, which triggers all the initialization from top to bottom. Then, the body of the secondary constructor is executed.

class Person(n: String, a: Int) {
   init {
       println("1st: initialization block 1 run")
   }

   var name: String = n.apply { println("2nd: initialization lines run") }
   var age: Int

   init {
       age = a
       println("3rd: initialization block 2 run")
   }

   constructor(p: Person) : this(p.name, p.age) {
       println("4th: secondary constructor run")
   }
}

Can I Skip the Primary Constructor?

No, a default primary constructor is still there even when you don’t write it and you are still required to call it in the secondary constructor. Also, you cannot initialize the variables in the secondary constructor because it has already passed the initialization timeframe. (Well, they are actually properties, but they behave just like variables in this case.)

class Person() {
   var name: String // Compile Error: Property must be initialized
   var age: Int // Compile Error: Property must be initialized

   constructor(n: String, a: Int) : this() {
       name = n
       age = a
   }
}

OK, if you really want to fake it like a Java constructor, here is the hack. It’s NOT recommended and I wrote it just for the learning purpose.

class Person() {
   var name: String = ""
   var age: Int = 0

   constructor(n: String, a: Int) : this() {
       name = n
       age = a
   }
}

What happened above is that we initialized name and age with a default value and assigned them to a new value in the secondary constructor. However, it doesn’t work when you replace var with val because Kotlin does not allow variable initialization in a secondary constructor.

Overloading Arguments with Default Value

Last, but not the least. Kotlin has this elegant way to overload arguments with default values.

class Person(n: String = "Nameless", a: Int = 1) {
   var name: String = n
   var age: Int = a
}

fun main(args: Array<String>) {
   var p1 = Person() // name: Nameless, age: 1
   var p2 = Person("Tom")  // name: Tom, age: 1
   var p3 = Person(a=5) // name: Nameless, age: 5
}

The primary constructor is actually a sweet requirement in Kotlin. You will always know what is expected to create the object by scanning the the primary constructor without having to look at all the constructors as you would in Java, because constructors are no longer independent of each other. The primary constructor is also easy to spot because it is the first line of the class. If you are starting on learning Kotlin, I think the constructor is a good starting point. I hope you find this post helpful.

Source: GameChanger