Skip to content

Kotlin (or Java) Enum Classes: The Good, the Bad and the Ugly

Enum classes stir up a lot of controversy in the Android world for a number of reasons, but they still prove to be used by experienced developers day by day. Why is this so?

(Heads up: while the syntax of the code here is going to be in Kotlin, all the information here applies for Java enum classes as well)

What is an Enum class?

Simply put, an Enum is a special class type that holds a list of constants. The most common usage of this is to represent different types of one particular object, or when a variable can only be one of a certain set of values.

enum class Direction {
    NORTH, SOUTH, EAST, WEST
}

The constants of an enum don’t necessarily require a value. Without a value, they can be used in validation through ifs and switch statements.

val directionToTreasure = Direction.NORTH

when(directionToTreasure) {
    Direction.NORTH -> indicateNorth()
    Direction.SOUTH -> indicateSouth()
    Direction.EAST -> indicateEast()
    Direction.WEST -> indicateWest()
}

Probably not the best way to handle these indicate functions, but you get the idea. At least it’ll be lots of fun

Their use can however be expanded to include values attached to each constant.

enum class Color(val rgb: Int) {
    RED(0xFF0000)
    GREEN(0x00FF00)
    BLUE(0x0000FF)
}

When you use enum classes this way, you can get their value like so:

val shirtColour = Color.BLUE
val color: Int = shirtColour.rgb

What else can an Enum do?

To put it in a nutshell, a fucking lot

Firstly, instead of constants, enums can be implemented anonymous classes with their own methods and overriding base methods.

enum class ProtocolState yadayada {

}

They can also implement interfaces in a similar fashion

enum class IntArithmetics yadayada {

}

Finally, enum has two constants which provide you with some pretty useful values.

val name: String // The name of the constant
val ordinal: Int // The position of the constant in the list of values

if (shirtColour.name == "BLUE") {
    // Do some blue stuff
}

In fact, thanks to the use of these constants, you can also conveniently map between enum and String/Int types.

Enum -> Int

yourEnum.ordinal

Int -> Enum

EnumType.values()[position]

String -> Enum

EnumType.valueOf(yourString)

Enum -> String

yourEnum.name

Credits to this guy on StackOverflow for sharing this mapping

What’s the purpose of Enum classes?

I get you, it’s not the most straightforward thing, but I’ll fill you in.

For the most part, enum classes are used to produce more readable code. When you have an object that can have multiple different types, it’s much more concise to identify them with a readable value than some arbitrary integer.

// Bad code
when(direction) {
    0 -> goNorth()
    1 -> goSouth()
    2 -> goEast()
    3 -> goWest()
}

// Good code
when(direction) {
    Direction.NORTH -> goNorth()
    Direction.SOUTH -> goSouth()
    Direction.EAST -> goEast()
    Direction.WEST -> goWest()
}

Another useful purpose of Enums are when you have data that comes in as a string but you need to eventually map it to an int value, like when your API gives your object’s type but you need to pass it into a RecyclerView Adapter which requires an Int for View types. I personally used this method in my enum class to make that happen.

@JvmStatic
fun getType(type: String): BlockType? =
        when(type) {
            "hero" -> ContentHero
            "products" -> ContentProductList
            else -> null
        }

Why you shouldn’t use Enum classes

I bet now you’re thinking “Hold up a second. You told me all about how to use Enums and now you’re just gonna tell me not to use them?”. Hear me out mate.

Simply put, Enums are expensive mate! I know mobile phones are getting better by the day but for one, there are still too many people out there with less powerful phones and two, the way we make apps and the libraries we use are using more memory as well.

This is old news. Enums would be a memory problem for phones running with Dalvik but that’s basically been discontinued in place of the ART (Android Runtime Machine). Added to the fact that even people in poorer countries have fairly powerful phones, and that Proguard can now optimise code better than ever, it’s safe to say that Enums no longer cause a problem in performance.

There are still a few alternatives you can use that can achieve similar results to an Enum class.

Constants

Constants are super concise as well. They hold a single value and give it a name. They are also extremely lightweight.

*Def

The *Def annotation is also great if you have a variable that only takes in certain values.

@IntDef({RED, GREEN, BLUE})

Why still pick Enums over these alternatives?

Where the enum shines much more so than its functional siblings is exhaustiveness. When used with Kotlin, you can use a switch statement like this

val foo = when(someEnum) {

}

And when you do, you’re forced to handle a case for every constant in your enum, otherwise your code won’t compile. With constants and *def annotations, the best you get given are lint warnings. Enums simply lead to safer code.

(Credits to u/-manabreak from Reddit for this)

So as long as your use of enums leads to more concise code for your application and especially in Kotlin’s case, better case safety, by all means, enumerate to your heart’s content.

 

 

Tags: