Kotlin Enum Classes


Enums are special classes which limit the possible values of an object for that class. The possible values defined for that class are final or unchangeable.

The easiest way to define an enum is
  
enum class Direction {
EAST, WEST, NORTH, SOUTH
}
Here each enum constant is an object.

For using these values
  
var direction : Direction = Direction.EAST

Base class of all Enum Classes

There is a base class for all enum classes which is defined in kotlin package.
  
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/

package kotlin

/**
* The common base class of all enum classes.
* See the [Kotlin language documentation](https://kotlinlang.org/docs/reference/enum-classes.html) for more
* information on enum classes.
*/
public abstract class Enum<E : Enum<E>>(name: String, ordinal: Int): Comparable<E> {
companion object {}

/**
* Returns the name of this enum constant, exactly as declared in its enum declaration.
*/
public final val name: String

/**
* Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant
* is assigned an ordinal of zero).
*/
public final val ordinal: Int

public override final fun compareTo(other: E): Int

/**
* Throws an exception since enum constants cannot be cloned.
* This method prevents enum classes from inheriting from `Cloneable`.
*/
protected final fun clone(): Any

public override final fun equals(other: Any?): Boolean
public override final fun hashCode(): Int
public override fun toString(): String

/**
* Returns an array containing the constants of this enum type, in the order they're declared.
* This method may be used to iterate over the constants.
* @values
*/

/**
* Returns the enum constant of this type with the specified name. The string must match exactly an identifier used to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.)
* @throws IllegalArgumentException if this enum type has no constant with the specified name
* @valueOf
*/
}

Name and Ordinal

These two properties are available by default for each enum constant as these are added in the base class itself.

Name is the actual name by which the enum constant is defined whereas ordinal is the sequence of that particular enum constant in the enum class having the first one starting from 0
  
val direction = Direction.NORTH
println(direction.name)
println(direction.ordinal)

// this will print
NORTH
2

Method overriding in Enum

As you can see in the base class, all functions are final and cannot be overridden except toString. we can override toString function for any or all object in that enum.

It is not compulsory to override for all. we can override for just one also.
  
enum class Direction {
EAST {
override fun toString(): String {
return "East direction"
}
},
WEST {
override fun toString(): String {
return "West direction"
}
},
NORTH {
override fun toString(): String {
return "North direction"
}
},
SOUTH {
override fun toString(): String {
return "South direction"
}
}
}

Variables in Enum class

Similar to any other class, we can have other variables also with each enum constant.
  
enum class Direction(val dirCode: Int) {
EAST(1),
WEST(2),
NORTH(3),
SOUTH(4)
}

val direction = Direction.WEST
println(direction.dirCode)

//this will print
2
You can even modify the variable according to the needs by declaring that variables as mutable or var
  
enum class Direction(var dirCode: Int) {
EAST(1),
WEST(2),
NORTH(3),
SOUTH(4)
}

val direction = Direction.WEST
Direction.WEST.dirCode = 10
println(direction.dirCode)

//this will print
10

Functions in Enum classes

Since all enum constants are objects and enum is a class, we can define any number of functions in the enum class or even can define an abstract function in enum class which will be implemented by the Enum objects.
  
enum class Direction(var dirCode: Int) {
EAST(1) {
override fun humanDirection(): String {
return "to Right side"
}
},
WEST(2) {
override fun humanDirection(): String {
return "to left side"
}
},
NORTH(3) {
override fun humanDirection(): String {
return "to up side"
}
},
SOUTH(4) {
override fun humanDirection(): String {
return "to down side"
}
};

abstract fun humanDirection(): String

fun doSomethingWithDirection(){
println(this.dirCode * 10)
}
}

val direction = Direction.EAST
direction.doSomethingWithDirection()
direction.humanDirection()

Interface implementation in Enum class

We can even define an interface and can implement it in any enum class. There are two ways an enum class can implement an interface. Either all the objects of that enum override the interface methods or the methods were implemented on the class level means common for all.
  
interface IDirection {
fun humanDirection(): String
}

interface Instructions {
fun generalDirections()
}

enum class Direction : IDirection, Instructions {
EAST {
override fun humanDirection(): String {
return "to Right side"
}
},
WEST {
override fun humanDirection(): String {
return "to left side"
}
},
NORTH {
override fun humanDirection(): String {
return "to up side"
}
},
SOUTH {
override fun humanDirection(): String {
return "to down side"
}
};

override fun generalDirections() {
println("take and map and compare directions")
}
}

val direction = Direction.EAST
direction.humanDirection()
direction.generalDirections()

Enum Constants (valueOf)

To convert a string value into an enum object, we can use valueOf function which will return us the enum constant by its name.
  
enum class Direction {
EAST, WEST, NORTH, SOUTH
}

val dir = Direction.valueOf("WEST")
println(dir.name)

//this will print
//WEST
We can even use a generic function which takes a type of input.
  
val dir = enumValueOf<Direction>("NORTH")
println(dir.name)

//this will print
//NORTH
Keep in mind that the above functions take the value which is case sensitive and throws an IllegalArgumentException if the specified name does not match with any of the enum constants defined in the class.

Enum Values

To get all the possible values in an array, we can use values or enumValues function which will return us an array of all the values in that enum class.
  
val allValues = Direction.values()
allValues.forEach{
println(it.name)
}

val allEnumValues = enumValues()
allEnumValues.forEach{
println(it.name)
}

Comparable in Enum class

Enum classes also implement Comparable interface which has compareTo method. It compares the position or ordinal in enum and returns the difference either in positive or negative integer or zero if equal.
  
val east = Direction.EAST
val north = Direction.NORTH

println(east.compareTo(north))
//this will print
//-2

println(north.compareTo(east))
//this will print
//2