(English) Kotlin Constructors

Není k dispozici v češtině.

Kotlin helps you make your code shorter and more readable in many areas. One of them is constructors. In Java you have to tediously assign all variables passed to the constructor in similar style

this.something = something 

If more constructors are required, you have to overload them and repeat yourself over and over. Like in the following example.

public class Person {

    private String firstName;
    private String lastName;
    private String email;
    private String phone;
    private String department;

    public Person(String firstName, String lastName) {
        this(firstName, lastName, null);
    }

    public Person(String firstName, String lastName, String email) {
        this(firstName, lastName, email, null);
    }

    public Person(String firstName, String lastName, String email, String phone) {
        this(firstName, lastName, email, phone, "ABC");
    }

    public Person(String firstName, String lastName, String email, String phone, String department) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
        this.phone = phone;
        this.department = department;
    }
}

Person can be then created like this.

 Person person = new Person("John", "Silver", "longjohn@pirates.com", null, null);

But is it really readable? If there are too many variables, you might consider Builder pattern to keep code readable.

public class PersonBuilder {

    private String firstName;
    private String lastName;
    private String email;
    private String phone;
    private String department;

    public PersonBuilder() {

    }

    public PersonBuilder withFirstName(String firstName) {
        this.firstName = firstName;
        return this;
    }

    public PersonBuilder withLastName(String lastName) {
        this.lastName = lastName;
        return this;
    }

    public PersonBuilder withEmail(String email) {
        this.email = email;
        return this;
    }

    public PersonBuilder withPhone(String phone) {
        this.phone = phone;
        return this;
    }

    public PersonBuilder withDepartment(String department) {
        this.department = department;
        return this;
    }


    public Person build() {
        return new Person(firstName, lastName, email, phone, department);
    }
    
}

and call it like this

Person person2 = new PersonBuilder()
                         .withFirstName("John")
                         .withLastName("Silver")
                         .withEmail("longjohn@pirates.com")
                         .build();

Quite a bit of code, right? With Kotlin it can be this short and simple.

class Person(private val firstName: String,
             private val lastName: String,
             private var email: String? = null,
             private var phone: String? = null,
             private var department: String = "ABC")

Let me explain what is happening here.
What is shown is a primary constructor. Kotlin class can have a primary constructor and also secondary constructors. Primary constructor goes after the class name. Class properties can be declared in constructor together with visibility modifiers or annotations and are initialized with passed values. In our example we passed two immutable values (val) and rest are mutable variables(var).
A constructor can also contain default values.

private var phone: String? = null,
private var department: String = "ABC"

These variables can be skipped in a constructor. But order has to be maintained and position of properties without default values have to be before those with default values.
But wait! Actually, you don’t need to keep order. You can call constructor with named arguments and then any order is valid.

var person = Person(email = "longjohn@pirates.com", lastName = "Silver", firstName = "John")

If you really need to have more constructors or perform some validity check in a constructor, you certainly can. Following is a secondary constructor.

private var isInsane: Boolean = false
    
constructor(firstName: String, lastName: String, isInsane: Boolean) : this(firstName, lastName) {
    this.isInsane = isInsane
}

Secondary constructor needs to delegate to primary constructor through this keyword.
You can also perform validation or any initialization logic with primary constructor. Let’s add age property and only allow creation of object if person is at least 18 years old.

class Person(private val firstName: String = "",
             private val lastName: String,
             private var email: String? = null,
             private var phone: String? = null,
             private var department: String = "ABC",
             private var age: Int) {
    init {
        if (age < 18) throw IllegalArgumentException("Underage")
    }
}