Enums

Enums are meant to represent variables which can only take values from a predefined set of possible values. Kotlin Enums provides a way to declare not only constant but also helps to write functions and properties inside enums, Enums avoids the type safety issues in kotlin

The OS example is a good one; an OS can be Linux, or Windows, but not Cheese or a Cat. Using an enum makes this real-world relationship part of the code (which is the whole point of OOP); unless you say so there is no way a variable of type OS can be set to anything other than a valid OS.

Yes, you could store OS names as an array of strings (or integers even).

But then how would you store assign a variable representing which OS you have? It would have to be something like


String myOS = "Android";

That might be okay, but what if you are doing that 20 times throughout your system? You might misspell it once or twice, you might decide to change the name, or you might decide not to support android at all.

Any change means you will have to go back and change every assignment and comparison of myOS, and any mistakes will be legal Kotlin.

Now below will look like value from enum.


OS myOS = OS.ANDROID

Unlike the previous code, this captures a type relationship. You (and the compiler) know what the variable myOS is supposed to be; a type of OS.

You can't by accident set myOS to be nonsensical, and most changes to the OS enum will cause compile errors if not reflected in the code.

To define Enums, we have to use the enum class keyword in kotlin, enum constants are separated with comma and each enum is an object in kotlin

values() returns the enum constants in the form of an array over which we can iterate to retrieve each enum constant.

valueOf() is used to fetch an enum constant using a String as the argument.

ordinal property retrieves the position of the constant in the enums


enum class OS{
    MICROSOFT, MAC, ANDROID, IOS, FIREFOX
}
fun main(args: Array<String>) {
    println(OS.MICROSOFT) //prints MICROSOFT
    println(OS.values().size) //prints 5
    println(OS.valueOf("ANDROID")) //prints ANDROID
    for (enum in OS.values()) {
        println(enum.name)
    }
    println(OS.valueOf("IOS")) //prints IOS
	
	// prints the position of the ANDROID
	println("position of ANDROID is : "+OS.ANDROID.ordinal)
}

If the value doesn’t match with any of the constants, a runtime exception would be thrown.

Each of the enum constants acts as separate instances of the class. Since enum constants are instances of an Enum class, the constants can be initialized by passing specific values to the constructor.


enum class CreditCardType(val color: String) {
    SILVER("Gray"),
    GOLD("Yellow"),
    PLATINUM("Black")
}
fun main(args: Array<String>) {
    val color = CreditCardType.SILVER.color
    println(color)
}

Getters and setter in kotlin

Enum with Properties and functions :

Kotlin Enums can contain not only constants but also we can have properties and functions inside the enum, Each of the enum constants acts as separate instances of the class.

We can access the functions and properties through the enum constants only


enum class OS{
    MICROSOFT, MAC, ANDROID, IOS, FIREFOX;
    fun printSomething(){
        println("functions inside an enum")
    };
    var iAmVariable = "Yes, I'm an string variable"
}
fun main(args: Array<String>) {
    OS.MAC.printSomething()
    println(OS.IOS.iAmVariable)
}

Inheritance in kotlin

Override Enum's toString() :

We can override the toString() function of the Enums, so when you access the constant in enums, it will call the toString() method by default and perform operation on the enum constants and return the value.

You can also access the default value by using the name property of the enum

I below example, I am overriding the toString() function in inside enum.


enum class OS{
    MICROSOFT, MAC, ANDROID, IOS, FIREFOX;
    override fun toString(): String {
        return super.toString().toLowerCase()
    }
}
fun main(args: Array<String>) {
    var enumVaue = OS.IOS
    var enumName = OS.IOS.name
    println("value from Override to string : $enumVaue")
    println("value from enum name : $enumName")
}

Kotlin's Enums as Anonymous classes :

Enum constants can behave as anonymous classes be implementing their own functions along with overriding base functions from the class as shown below.


enum class OS(var whoOwns:String){
    MICROSOFT("Bill"){
        override fun printLengthOfOwnerName(){
            println(whoOwns.length)
        }
    },
    MAC("Steve"){
        override fun printLengthOfOwnerName(){
            println(whoOwns.length)
        }
    };
    abstract fun printLengthOfOwnerName()
}
fun main(args: Array<String>) {
    var length = OS.MAC.printLengthOfOwnerName()
}

Kotlin's Enum Inheritance from Interfaces :

We have inherit an interface in enums, in above example you have seen how enums can behave like anonymous classes.

Lets use the same anonymous classes to implement interface, enum is inheriting from the interface


interface Length {
    abstract fun printLengthOfOwnerName()
}
enum class OS(var whoOwns:String):Length{
    MICROSOFT("Bill"){
        override fun printLengthOfOwnerName(){
            println(whoOwns.length)
        }
    },
    MAC("Steve"){
        override fun printLengthOfOwnerName(){
            println(whoOwns.length)
        }
    };
}
fun main(args: Array<String>) {
    var length = OS.MAC.printLengthOfOwnerName()
}

Generic Constraints

Enums inside Enums in Kotlin :

We can create the enums inside the enums in kotlin.


enum class Months{
    MARCH,
    APRIL,
    JUNE;
    enum class Day{
        MONDAY,
        TUESDAY,
        WEDNESDAY
    }
}
fun main(args: Array<String>) {
    var dayFromMonth = Months.Day.MONDAY
    println(dayFromMonth)
}

The inner Enum class Day cannot be invoked from the enum constants.

Collections

When construct with Enum :

Sometimes in you application you might want to accept a specific set of values like OS values, in those cases you can use the Enums in kotlin.

Enums can be used in kotlin's when construct, We must need to use the else block to handle if we receive any value other Than value present in the Enum.


fun osValue(os:OS){
    when(os){
        OS.MICROSOFT -> println("This is Microsoft OS")
        OS.MAC -> println("This is Mac os")
        OS.ANDROID -> println("This is Android os")
        OS.IOS -> println("This is IOS OS")
        OS.FIREFOX -> println("This is firefox OS")
        else ->{
            print("Provide only value from OS enum")
        }
    }
}
fun main(args: Array<String>) {
    osValue(OS.MAC)
}

KClass in Kotlin Reflection

Sealed Classes in Kotlin

Sealed class restricts the class hierarchy. A class can be declared as sealed class using sealed keyword before the class name. Sealed class is used to represent restricted class hierarchy.

All the classes in the kotlin are sealed class by default, sealed classes do not allow inheritance (in other files)

Put below code in file1.kt


sealed class Phone{
    fun wiFi(){
        println("this has wifi")
    }
}

Put below code in file2.kt


class Mobile:Phone(){
    fun call() {
        println("Dialing thru qwerty keys")
    }
}
fun main(args: Array<String>) {
    val derivedPhone = Mobile()
    derivedPhone.call()
    derivedPhone.wiFi()
}

If you run above code you may face below error:

Error:(1, 14) Kotlin: Cannot access '': it is private in 'Phone'

Sealed classes are not allowed to have non-private constructors because their constructors are private by default.

A sealed class can have subclasses, but all of them must be declared in the same file as the sealed class itself.


sealed class Phone{
    fun wiFi(){
        println("this has wifi")
    }
}
class Mobile:Phone(){
    fun call() {
        println("Dialing thru qwerty keys")
    }
}
fun main(args: Array<String>) {
    val derivedPhone = Mobile()
    derivedPhone.call()
    derivedPhone.wiFi()
}

A sealed class is abstract by itself, it cannot be instantiated directly and can have abstract members.

I below code I have tried to create instance of sealed class in kotlin, it throws error.

Error:(26, 15) Kotlin: Cannot access '': it is private in 'Phone'

Error:(26, 15) Kotlin: Sealed types cannot be instantiated

sealed class Phone{
    fun wiFi(){
        println("this has wifi")
    }
}
fun main(args: Array<String>) {
    val pho = Phone()
}

We can inherit the sub classes of the sealed class in kotlin, also we can place them in any file as we want. We can create object for the subclass of the sealed class in kotlin.

Put below code in file1.kt


sealed class Phone{
    fun wiFi(){
        println("this has wifi")
    }
    open class Animal{
        fun sound(){
            println("urrrr")
        }
    }
}

Put below code in file2.kt


class Cat():Phone.Animal(){
    fun look(){
        println("cat looks pluffy")
    }
}
fun main(args: Array<String>) {
    var c = Cat()
    c.look()
    c.sound()
    // create instance to subclass of sealed class
    var an = Phone.Animal()
    an.sound()
}

Read Properties File in Kotlin

when construct with Sealed classes :

Sealed classes are mostly used with when construct as expression and the its sub classes as cases in when. And you do not need to have a else block in the when construct

On big advantage about sealed classes with when construct is, you cannot add sub classes without adding them to when construct, if you try so kotlin will throw error


sealed class Phone
class Apple:Phone()
class Android:Phone()
class BlackBerry:Phone()
fun checkPhoneDetails(ph:Phone) =
    when(ph){
        is Apple -> println("This does not taste like apple")
        is Android -> println("This comes with many food flavors")
        is BlackBerry -> println("This not season for Blackberries")
    }
fun main(args: Array<String>) {
    checkPhoneDetails(Apple())
}

Lets try to add Pixel phone as sub class to the Phone but do not add to when construct, now when construct will throw error.

'when' expression must be exhaustive, add necessary 'is Pixel' branch or 'else' branch instead

sealed class Phone
class Apple:Phone()
class Android:Phone()
class BlackBerry:Phone()
class Pixel:Phone()
fun checkPhoneDetails(ph:Phone) =
    when(ph){
        is Apple -> println("This does not taste like apple")
        is Android -> println("This comes with many food flavors")
        is BlackBerry -> println("This not season for Blackberries")
    }
fun main(args: Array<String>) {
    checkPhoneDetails(Apple())
}

CSV files in kotlin

aaaaaaaaaaaaa
Comment / Suggestion Section
Point our Mistakes and Post Your Suggestions

Recent Addition

new tutorial Selenium Online Training : Our next online training course for Selenium with Java starts from 17th December 2018.

You can attend first 3 classes for free, the total course fee is INR 10,000

The course time would be 8.00 PM(IST) for the first three classes

If you are interested to learn, then you can join the course by sending email to chercher.tech@gmail.com

or Register below


 
Join My Facebook Group
Join Group