Я пытаюсь найти лучший способ выполнить «обратный поиск» в перечислении в Котлине. Один из моих выводов из Effective Java заключался в том, что вы вводите статическую карту внутри перечисления для обработки обратного поиска. Перенос этого на Kotlin с помощью простого перечисления приводит меня к такому коду:
enum class Type(val value: Int) {
A(1),
B(2),
C(3);
companion object {
val map: MutableMap<Int, Type> = HashMap()
init {
for (i in Type.values()) {
map[i.value] = i
}
}
fun fromInt(type: Int?): Type? {
return map[type]
}
}
}
Мой вопрос: это лучший способ сделать это или есть лучший способ? Что, если у меня есть несколько перечислений, которые следуют аналогичному шаблону? Есть ли в Kotlin способ сделать этот код более пригодным для повторного использования в перечислениях?
Ответы:
Прежде всего, аргументом
fromInt()
должно быть не значениеInt
, а объектInt?
. Попытка получитьType
using null, очевидно, приведет к null, и вызывающей стороне даже не следует пытаться это сделать.Map
Не имеет также никаких оснований быть изменяемым. Код можно сократить до:Этот код настолько короткий, что, честно говоря, я не уверен, что стоит пытаться найти решение многократного использования.
источник
fromInt
return ненулевым, напримерEnum.valueOf(String)
:map[type] ?: throw IllegalArgumentException()
by lazy{}
дляmap
иgetOrDefault()
для более безопасного доступаvalue
Type.fromInt()
из кода Java вам нужно будет аннотировать метод с помощью@JvmStatic
.мы можем использовать
find
which Возвращает первый элемент, соответствующий данному предикату, или null, если такой элемент не был найден.источник
first { ... }
Вместо этого используется очевидное усовершенствование, потому что нет смысла использовать несколько результатов.first
не является улучшением, поскольку оно изменяет поведение и выдает ошибку,NoSuchElementException
если элемент не найден,find
что равноfirstOrNull
возвратуnull
. так что, если вы хотите бросить вместо возврата null usefirst
fun valueFrom(valueA: Int, valueB: String): EnumType? = values().find { it.valueA == valueA && it.valueB == valueB }
Также вы можете генерировать исключение, если значения не находятся в перечислении:fun valueFrom( ... ) = values().find { ... } ?: throw Exception("any message")
или вы можете использовать его при вызове этого метода:var enumValue = EnumType.valueFrom(valueA, valueB) ?: throw Exception( ...)
В данном случае это не имеет особого смысла, но вот "логическое извлечение" для решения @ JBNized:
В общем, дело в том, что сопутствующие объекты можно использовать повторно (в отличие от статических членов в классе Java)
источник
Другой вариант, который можно было бы назвать более «идиоматическим», был бы следующим:
Который потом можно использовать как
Type[type]
.источник
Я обнаружил, что выполняю обратный поиск по индивидуальному заказу, вручную кодирую, значение пару раз и придумал следующий подход.
Заставить
enum
реализовать общий интерфейс:Этот интерфейс (как ни странно его название :)) помечает определенное значение как явный код. Цель состоит в том, чтобы уметь писать:
Этого легко добиться с помощью следующего кода:
источник
Вариант некоторых предыдущих предложений может быть следующим, с использованием порядкового поля и getValue:
}
источник
Другой пример реализации. Это также устанавливает значение по умолчанию (здесь
OPEN
), если вход не соответствует параметру перечисления:}
источник
Придумал более общее решение
Пример использования:
источник
Истинный идиоматический котлинский путь. Без раздутого кода отражения:
источник
Немного расширенный подход принятого решения с нулевой проверкой и функцией вызова
источник
val t = Type.values () [порядковый номер]
:)
источник