Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating multiple Kotlin constructors that do not share common paramaters

Lets say I have a simple data class that can be serialized to a string:

class Time(val hours: Int, val minutes: Int, val seconds: Int) {
    fun serialize(): String {
        return "%02d:%02d:%02d".format(hours, minutes, seconds)
    }
}

How can I add a second constructor that allows me to construct this object using a serialized String? I expected to be able to use

constructor(serializedString: String) {
    val subs = serializedString.split(":")
    return Time(subs[0].toInt(),subs[1].toInt(),subs[2].toInt())
}

But come to find out that secondary constructors need to actually override the primary constructor. Obviously my secondary constructor in no way shape or form resembles my primary constructor.

  • Is the correct answer here to simply make a companion object that contains a static deserialize method?
  • Is there no way in Kotlin to make multiple constructors that accept different kinds of arguments?
  • Or is the problem that I simply shouldn't have a primary constructor at all?
like image 422
JHixson Avatar asked Jan 02 '23 22:01

JHixson


2 Answers

Just do not use primary constructor. Use two different secondary constructors:

class Time {

    val hours: Int
    val minutes: Int
    val seconds: Int

    constructor(hours: Int, minutes: Int, seconds: Int) {
        this.hours = hours
        this.minutes = minutes
        this.seconds = seconds
    }

    constructor(serializedString: String) {
       val subs = serializedString.split(":")
       this.hours = subs[0].toInt()
       this.minutes = subs[1].toInt()
       this.seconds = subs[2].toInt()
    }

    fun serialize(): String{
        return "{%02d}:{%12d}:{%22d}".format(hours,minutes,seconds)
    }
}

In case if you need data class and equals/hashCode it will be better to use primary constructor with factory method in companion object.

like image 93
hluhovskyi Avatar answered Jan 05 '23 15:01

hluhovskyi


Since hours, minutes and seconds are properties of you class you can as well put them in a primary construtor and let the secondary call the primary one:

class Time(val hours: Int, val minutes: Int, val seconds: Int) {

    constructor(serializedString: String) : this(
        serializedString.split(":")[0].toInt(),
        serializedString.split(":")[1].toInt(),
        serializedString.split(":")[2].toInt()
    )

    fun serialize(): String {
        return "{%02d}:{%12d}:{%22d}".format(hours, minutes, seconds)
    }
}

Add the data keyword if you need it to be a data class.

Don't worry about serializedString.split(":") being called three times, it should not have any significant performance impact.

like image 22
Willi Mentzel Avatar answered Jan 05 '23 16:01

Willi Mentzel