kotlin safe conversion from string to enum

16,905

Solution 1

You don't want an extension since they must be invoked on an existing object. You want a top-level function. There is a built in one You can use:

/**
 * Returns an enum entry with specified name.
 */
@SinceKotlin("1.1")
public inline fun <reified T : Enum<T>> enumValueOf(name: String): T

You can call it by inferring the type, or explicitly:

val a : MyEnumClass = enumValueOf("A")
val b = enumValueOf<MyEnumClass>("B")

However this method is not nullable: it throws java.lang.IllegalArgumentException on unknown values.

But it's easy to mimick it's behavior and have it work for nullable enums with a top level function:

inline fun <reified T : Enum<*>> enumValueOrNull(name: String): T? =
    T::class.java.enumConstants.firstOrNull { it.name == name }

Solution 2

Colors.values().find { it.name == "Yellow" }

Solution 3

You can use something like this :

inline fun <reified T : Enum<T>> String.asEnumOrDefault(defaultValue: T? = null): T? =
    enumValues<T>().firstOrNull { it.name.equals(this, ignoreCase = true) } ?: defaultValue

Then: "Yellow".asEnumOrDefault(Colors.Green)

Or, if you it can't be infered: "Yellow".asEnumOrDefault<Colors>()

Share:
16,905

Related videos on Youtube

innov8
Author by

innov8

Updated on September 14, 2022

Comments

  • innov8
    innov8 over 1 year

    I need to convert strings to Enum values, but want a function which returns null if the string is not an enum.

    enum class Colors{
       Red, Green, Blue
    
    } 
    

    I can used Colors.valueOf(testString) provided testString is value, but there will be an exception if it is not valid, and I want a null in that case.

    Because I want to this often, an extension function would be ideal. But the extension needs to operate on the class Colors, and not an object of type Colors.

    Anyone know how to write such an extension? Ideally one that is generic for any enum class.

    It is simple to write a top level function, but I am seeking one that acts as the standard 'method' does

    // instead of 
    val willGetAnException = Colors.valueOf("Yellow") // standard existing fun
    val willGetNull = Colors.valueOrNullOf("Orange")  // new fun i seek
    

    And ideally one that is generic and works for any enum

  • innov8
    innov8 over 5 years
    Thanks... that is about the point i got to as well..... if i make that function a method of the companion object of the class (and take out the generic) I can call it the way i wish.
  • Pawel
    Pawel over 5 years
    If you want it to be limited to single enum class you could have added method in companion object that wraps valueOf with a try-catch block.
  • innov8
    innov8 over 5 years
    Thanks... that is about the point i got to as well. A top level function which is not what i want. Sort of one step further ..... if i make that function a method of the companion object of the enum class (and take out the generic) I can call it the way i wish. But how to have a generic method apply to the companion object of all enum classes is what i was hoping for,
  • con
    con over 3 years
    a verbal explanation is often helpful
  • Emanuel Moecklin
    Emanuel Moecklin about 3 years
    This is a very simple and elegant solution without the need for extension functions. You can also define a default value using the Elvis operator: Colors.values().find { it.name == "Yellow" } ?: Colors.Red
  • Denis Pavlov
    Denis Pavlov over 2 years
    This is an elegant solution. Thanks.
  • Mick Sear
    Mick Sear over 2 years
    Best solution IMHO. If you want to default it then just do val colour = Colors.values().find { it.name == "Yellow" } ?: Colors.UNKNOWN or something like that.