How do I create an enum from a string in Kotlin? - kotlin

I have an enum with some instances Foo and Bar. If I have a string "Foo", how can I instantiate a Foo enum from that? In C# it would be Enum.Parse(...), is there an equivalent in Kotlin?
Currently, the best I have found is to create a factory that switches on all possible strings, but that is error prone and performs poorly for large enumerations.

Kotlin enum classes have "static" function valueOf to get enum entry by string(like Java enums). Additionally they have "static" function values to get all enum entries. Example:
enum class MyEnum {
Foo, Bar, Baz
}
fun main(args : Array<String>) {
println(MyEnum.valueOf("Foo") == MyEnum.Foo)
println(MyEnum.valueOf("Bar") == MyEnum.Bar)
println(MyEnum.values().toList())
}

As bashor suggested, use MyEnum.valueOf() but please have in mind that it throws an exception if value can't be found. I recommend using:
enum class MyEnum {
Foo, Bar, Baz
}
try {
myVar = MyEnum.valueOf("Qux")
} catch(e: IllegalArgumentException) {
Log.d(TAG, "INVALID MyEnum value: 'Qux' | $e")
}

Would do it like
enum class MyEnum {
Foo, Bar, Baz
}
val value = MyEnum.values().firstOrNull {it.name == "Foo"} // results to MyEnum.Foo

Reusable Exception Safe Solution
The default solution in Kotlin will throw an exception. If you want a reliable solution that works statically for all enums, try this!
Now just call valueOf<MyEnum>("value"). If the type is invalid, you'll get null and have to handle it, instead of an exception.
inline fun <reified T : Enum<T>> valueOf(type: String): T? {
return try {
java.lang.Enum.valueOf(T::class.java, type)
} catch (e: Exception) {
null
}
}
Alternatively, you can set a default value, calling valueOf<MyEnum>("value", MyEnum.FALLBACK), and avoid a null response. You can extend your specific enum to have the default be automatic
inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T {
return try {
java.lang.Enum.valueOf(T::class.java, type)
} catch (e: Exception) {
default
}
}
Or if you want both, make the second:
inline fun <reified T : Enum<T>> valueOf(type: String, default: T): T = valueOf<T>(type) ?: default

If you want to create an enum value from one of its parameters, instead of the name, this funny code does a pretty decent job:
inline fun <reified T : Enum<T>, V> ((T) -> V).find(value: V): T? {
return enumValues<T>().firstOrNull { this(it) == value }
}
This can be used like this:
enum class Algorithms(val string: String) {
Sha1("SHA-1"),
Sha256("SHA-256"),
}
fun main() = println(
Algorithms::string.find("SHA-256")
?: throw IllegalArgumentException("Bad algorithm string: SHA-256")
)
This will print Sha256

I think the best solution is enumValueOf<T>(String):
enum class MyEnum { Foo, Bar }
#Test
fun test() {
assertEquals(MyEnum.Foo, enumValueOf<MyEnum>("Foo"))
}

Related

How to overload function with different return types and the same parameters in Kotlin?

I want to overload function with the same parameters (or without parameters at all) and different return types. Correct implementation should be chosen by the type of variable I assign returning value of a function to.
The only way to do this I found is using reified generics and comparing KClass'es:
inline fun <reified T: Any> read(): T {
return read(T::class)
}
#Suppress("UNCHECKED_CAST")
fun <T: Any> read(t: KClass<T>): T {
return when (t) {
Int::class -> readInt() as T
UInt::class -> readUInt() as T
String::class -> readString() as T
// ...
else -> throw Exception("Unsupported type")
}
}
fun readInt(): Int {
// ...
}
fun readUInt(): UInt {
// ...
}
fun readString(): String {
// ...
}
The problem with this approach is that the compiler and IDEA are not smart enough to determine types at compile time for which there is no implementation. The most I can do is throw a runtime exception:
val int: Int = read()
val string: String = read()
val double: Double = read()
// ^^^^ No compile-time error here
Maybe I'm missing something and there is more "correct" way of doing this?
Maybe I'm missing something and there is more "correct" way of doing this?
No. You cannot do this at all. You must name the methods differently.

Kotlin: access companion data in generic function

I have a simple task in Kotlin of listing enum values:
interface DisplayableEnum<E: Enum<E>> {
val displayValue: String
}
inline fun <reified T> printAllValues(selected: T?) where T: Enum<T>, T: DisplayableEnum<T> {
println("All Values:")
enumValues<T>().forEach {
println(it.displayValue)
}
selected?.let { println("\nSelected: ${it.displayValue}") }
}
////// USAGE
enum class MyEnum(override val displayValue: String): DisplayableEnum<MyEnum> {
A("value is A"),
B("value is B")
}
fun main() {
// with a selected value
f(MyEnum.A)
// without a selected value
f(null as MyEnum?)
}
Now imagine that all the enums I pass to printAllValues should also have a field called defaultValue. In case of MyEnum I would write it the following way:
enum class MyEnum(override val displayValue: String): DisplayableEnum<MyEnum> {
A("value is A"),
B("value is B");
companion object {
val defaultValue = A
}
}
So my question: is there a way to define such a contract in Kotlin?
Ideally, I would like to somehow define that contract in an interface, like DisplayableEnum above, and then somehow use it in printAllValues like this:
inline fun <reified T> printAllValues(selected: T) where T: Enum<T>, T: DisplayableEnum<T> {
println("All Values:")
enumValues<T>().forEach {
println(it.displayValue)
}
selected?.let { println("\nSelected: ${it.displayValue}") }
println("Default value: ${T.defaultValue???}"
}
The one thing that I don't want is using non-companion defaultValue, I always have to either pass it to the function manually (but why if the type contains all the info?) or, if made non-companion:
interface DisplayableEnum<E: Enum<E>> {
val displayValue: String
val defaultValue: E
}
then access it through an object - do something ugly like enumValues<T>().first().defaultValue.
I wonder if Kotlin has a solution in this case.
It's impossible to define abstract properties in companion object.
So it should be defined in interface directly.
The tricky part here is implementing of this interface without compiler warnings:
enum class MyEnum(override val displayValue: String) : DisplayableEnum<MyEnum> {
A("value is A"),
B("value is B");
override val defaultValue: MyEnum by lazy { A }
}
If enumValues<T>().first().defaultValue looks ugly to you, wrap it into auxilary function:
inline fun <reified T> enumDefaultValue(): T where T : Enum<T>, T : DisplayableEnum<T> =
enumValues<T>().first().defaultValue
//Usage:
println("Default value: ${enumDefaultValue<T>()}")

Kotlin extension function - compiler cannot infer that nullable is not null

Let's say I have a simple class Foo with a nullable String?
data class Foo(
val bar: String?
)
and I create a simple function capitalize
fun captitalize(foo: Foo) = when {
foo.bar != null -> runCatching { foo.bar.capitalize() }
else -> ""
}
which works fine, because the compiler infers that foo.bar cannot be null eventhough it's type is nullable. But then I decide to write the same function as an extension of Foo
fun Foo.captitalize2() = when {
bar != null -> runCatching { bar.capitalize() }
else -> ""
}
and all of a sudden the compiler is no longer able to infer that bar is not null, and IntelliJ tells me that "only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable reciever of type String?"
Can anyone explain why?
I think it's because in the first case you are calling this function:
public inline fun <R> runCatching(block: () -> R): Result<R> {
return try {
Result.success(block())
} catch (e: Throwable) {
Result.failure(e)
}
}
but in the second case you are calling function with receiver:
public inline fun <T, R> T.runCatching(block: T.() -> R): Result<R> {
return try {
Result.success(block())
} catch (e: Throwable) {
Result.failure(e)
}
}
For me, it looks like an issue in the Kotlin compiler because if you inline code of this function by yourself it will work fine:
fun Foo.captitalize2() = when {
bar != null -> try {
Result.success(bar.capitalize())
} catch (e: Throwable) {
Result.failure<String>(e)
}
else -> ""
}
btw, if I were you I would like to write my capitalize2 function like this :)
fun Foo.captitalize2() = bar?.capitalize() ?: ""
So, finally I found an alternative approach that allows us to use runCatching without having the problem you shows.
As in my comment to the answer of #Andrei Tanana, in your code type parameters of fun <T, R> T.runCatching(block: () -> R) : Result<R> are inferred as <Foo, String> and the compiler can't use the information that this.bar is not null.
If you rewrite the capitalize2 function as follows
fun Foo.capitalize2(): Serializable = when {
bar != null -> bar.runCatching { capitalize() }
else -> ""
}
T is inferred as String (thanks of the bar != null case of the when expression) and the compiler does not complain about this.capitalize() invocation in the block passed to runCatching.
I hope this can help you, both as an approach than allows you to solve the problem and as explanation of the problem itself.

How do I create an enum from an Int in Kotlin?

I have this enum:
enum class Types(val value: Int) {
FOO(1)
BAR(2)
FOO_BAR(3)
}
How do I create an instance of that enum using an Int?
I tried doing something like this:
val type = Types.valueOf(1)
And I get the error:
Integer literal does not conform to the expected type String
enum class Types(val value: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
fun fromInt(value: Int) = Types.values().first { it.value == value }
}
}
You may want to add a safety check for the range and return null.
Enum#valueOf is based on name. Which means in order to use that, you'd need to use valueof("FOO"). The valueof method consequently takes a String, which explains the error. A String isn't an Int, and types matter. The reason I mentioned what it does too, is so you know this isn't the method you're looking for.
If you want to grab one based on an int value, you need to define your own function to do so. You can get the values in an enum using values(), which returns an Array<Types> in this case. You can use firstOrNull as a safe approach, or first if you prefer an exception over null.
So add a companion object (which are static relative to the enum, so you can call Types.getByValue(1234) (Types.COMPANION.getByValue(1234) from Java) over Types.FOO.getByValue(1234).
companion object {
private val VALUES = values()
fun getByValue(value: Int) = VALUES.firstOrNull { it.value == value }
}
values() returns a new Array every time it's called, which means you should cache it locally to avoid re-creating one every single time you call getByValue. If you call values() when the method is called, you risk re-creating it repeatedly (depending on how many times you actually call it though), which is a waste of memory.
Admittedly, and as discussed in the comments, this may be an insignificant optimization, depending on your use. This means you can also do:
companion object {
fun getByValue(value: Int) = values().firstOrNull { it.value == value }
}
if that's something you'd prefer for readability or some other reason.
The function could also be expanded and check based on multiple parameters, if that's something you want to do. These types of functions aren't limited to one argument.
If you are using integer value only to maintain order, which you need to access correct value, then you don't need any extra code. You can use build in value ordinal. Ordinal represents position of value in enum declaration.
Here is an example:
enum class Types {
FOO, //Types.FOO.ordinal == 0 also position == 0
BAR, //Types.BAR.ordinal == 1 also position == 1
FOO_BAR //Types.FOO_BAR.ordinal == 2 also position == 2
}
You can access ordinal value simply calling:
Types.FOO.ordinal
To get correct value of enum you can simply call:
Types.values()[0] //Returns FOO
Types.values()[1] //Returns BAR
Types.values()[2] //Returns FOO_BAR
Types.values() returns enum values in order accordingly to declaration.
Summary:
Types.values(Types.FOO.ordinal) == Types.FOO //This is true
If integer values don't match order (int_value != enum.ordinal) or you are using different type (string, float...), than you need to iterate and compare your custom values as it was already mentioned in this thread.
It really depends on what you actually want to do.
If you need a specific hardcoded enum value, then you can directly use Types.FOO
If you are receiving the value dynamically from somewhere else in your code, you should try to use the enum type directly in order not to have to perform this kind of conversions
If you are receiving the value from a webservice, there should be something in your deserialization tool to allow this kind of conversion (like Jackson's #JsonValue)
If you want to get the enum value based on one of its properties (like the value property here), then I'm afraid you'll have to implement your own conversion method, as #Zoe pointed out.
One way to implement this custom conversion is by adding a companion object with the conversion method:
enum class Types(val value: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
private val types = values().associate { it.value to it }
fun findByValue(value: Int): Types? = types[value]
}
}
Companion objects in Kotlin are meant to contain members that belong to the class but that are not tied to any instance (like Java's static members).
Implementing the method there allows you to access your value by calling:
var bar = Types.findByValue(2) ?: error("No Types enum value found for 2")
Note that the returned value is nullable, to account for the possibility that no enum value corresponds to the parameter that was passed in. You can use the elvis operator ?: to handle that case with an error or a default value.
If you hate declaring for each enum type a companion object{ ... } to achieve EMotorcycleType.fromInt(...). Here's a solution for you.
EnumCaster object:
object EnumCaster {
inline fun <reified E : Enum<E>> fromInt(value: Int): E {
return enumValues<E>().first { it.toString().toInt() == value }
}
}
Enum example:
enum class EMotorcycleType(val value: Int){
Unknown(0),
Sport(1),
SportTouring(2),
Touring(3),
Naked(4),
Enduro(5),
SuperMoto(6),
Chopper(7),
CafeRacer(8),
.....
Count(9999);
override fun toString(): String = value.toString()
}
Usage example 1: Kotlin enum to jni and back
fun getType(): EMotorcycleType = EnumCaster.fromInt(nGetType())
private external fun nGetType(): Int
fun setType(type: EMotorcycleType) = nSetType(type.value)
private external fun nSetType(value: Int)
---- or ----
var type : EMotorcycleType
get() = EnumCaster.fromInt(nGetType())
set(value) = nSetType(value.value)
private external fun nGetType(): Int
private external fun nSetType(value: Int)
Usage example 2: Assign to val
val type = EnumCaster.fromInt<EMotorcycleType>(aValidTypeIntValue)
val typeTwo : EMotorcycleType = EnumCaster.fromInt(anotherValidTypeIntValue)
A naive way can be:
enum class Types(val value: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
fun valueOf(value: Int) = Types.values().find { it.value == value }
}
}
Then you can use
var bar = Types.valueOf(2)
Protocol orientated way with type-safety
interface RawRepresentable<T> {
val rawValue: T
}
inline fun <reified E, T> valueOf(value: T): E? where E : Enum<E>, E: RawRepresentable<T> {
return enumValues<E>().firstOrNull { it.rawValue == value }
}
enum class Types(override val rawValue: Int): RawRepresentable<Int> {
FOO(1),
BAR(2),
FOO_BAR(3);
}
Usage
val type = valueOf<Type>(2) // BAR(2)
You can use it on non-integer type, too.
I would build the 'reverse' map ahead of time. Probably not a big improvement, but also not much code.
enum class Test(val value: Int) {
A(1),
B(2);
companion object {
val reverseValues: Map<Int, Test> = values().associate { it.value to it }
fun valueFrom(i: Int): Test = reverseValues[i]!!
}
}
Edit: map...toMap() changed to associate per #hotkey's suggestion.
try this...
companion object{
fun FromInt(v:Int):Type{
return Type::class.java.constructors[0].newInstance(v) as Type
}
}
This is for anyone looking for getting the enum from its ordinal or index integer.
enum class MyEnum { RED, GREEN, BLUE }
MyEnum.values()[1] // GREEN
Another solution and its variations:
inline fun <reified T : Enum<T>> enumFromIndex(i: Int) = enumValues<T>()[i]
enumFromIndex<MyEnum>(1) // GREEN
inline fun <reified T : Enum<T>> enumFromIndex(i: Int) = enumValues<T>().getOrNull(i)
enumFromIndex<MyEnum>(3) ?: MyEnum.RED // RED
inline fun <reified T : Enum<T>> enumFromIndex(i: Int, default: T) =
enumValues<T>().getOrElse(i) { default }
enumFromIndex(2, MyEnum.RED) // BLUE
It is an adapted version of another answer. Also, thanks to Miha_x64 for this answer.
Another option...
enum class Types(val code: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
val map = values().associate { it.code to it }
// Get Type by code with check existing codes and default
fun getByCode(code: Int, typeDefault_param: Types = FOO): Types {
return map[code] ?: typeDefault_param
}
}
}
fun main() {
println("get 3: ${Types.getByCode(3)}")
println("get 10: ${Types.getByCode(10)}")
}
get 3: FOO_BAR
get 10: FOO

Kotlin: How to check if enum contains a given String without messing with Exceptions?

Why there is no contains method in enum classes (as well as in Java)? And how to implement it elegantly? Now I'm using this ugly approach:
val contains: Boolean =
try {
MyEnum.valueOf("some string")
true
} catch (e: IllegalArgumentException) {
false
}
enumContains
You can create an enumContains function similar to Hound Dog's answer but using reified type parameters instead.
You cannot create a JVM independent solution in Kotlin 1.0 but you can in Kotlin 1.1 using enumValues.
Kotlin 1.1
/**
* Returns `true` if enum T contains an entry with the specified name.
*/
inline fun <reified T : Enum<T>> enumContains(name: String): Boolean {
return enumValues<T>().any { it.name == name}
}
Kotlin 1.0
/**
* Returns `true` if enum T contains an entry with the specified name.
*/
inline fun <reified T : Enum<T>> enumContains(name: String): Boolean {
return T::class.java.enumConstants.any { it.name == name}
}
Usage
enumContains<MyEnum>("some string") // returns true or false
enumValueOfOrNull
If you also need the actual enum entry then you might consider creating an enumValueOfOrNull function instead.
Kotlin 1.1
/**
* Returns an enum entry with the specified name or `null` if no such entry was found.
*/
inline fun <reified T : Enum<T>> enumValueOfOrNull(name: String): T? {
return enumValues<T>().find { it.name == name }
}
Kotlin 1.0
/**
* Returns an enum entry with the specified name or `null` if no such entry was found.
*/
inline fun <reified T : Enum<T>> enumValueOfOrNull(name: String): T? {
return T::class.java.enumConstants.find { it.name == name }
}
Usage
enumValueOfOrNull<MyEnum>("some string")
You can just take values Array of your enum and use contains over it. For example:
Planets.values().map { it.name }.contains("EARTH")
But for this you need to have correct string value so you might uppercase it before search.
If you want to find enum by its value take a look at the Reverse Lookup for enums.
Edit:
As #JamesBassett suggested you can optimize it to stop looking once it finds a match.
Planets.values().any { it.name == "EARTH" }
You could do something like this:
fun <T : Enum<*>> KClass<T>.contains(value: String): Boolean {
return this.java.enumConstants.any { it.name == value }
}
MyEnum::class.contains("some string")
or if you are really adventurous
enum MyEnum {
MY_1, MY_2;
companion object {
fun isInEnum(someString: String) {
return try {
valueOf(someString)
true
} catch (e: Exception) {
false
}
}
}
}