Одна из главных задач разработчика — писать лаконичный код и избегать дублирования. Обобщения (generics) относятся к числу функциональностей, которые улучшают производительность, способствуют созданию меньших объемов кода и сокращению случаев его переиспользования и т. д. Следовательно, с ними обязательно нужно познакомиться.
Зачем нужны обобщения?
class SearchUtil(private val list: List<Int>) {
fun searchItem(element: Int, foundItem: (element: Int?) -> Unit) {
val itemFoundList = list.filter {
it == element
}
if (itemFoundList.isNullOrEmpty())
foundItem(null)
else
foundItem(itemFoundList.first())
}
}
fun search() {
val searchUtil = SearchUtil(listOf(25, 46, 35))
searchUtil.searchItem(element = 25) {
println("Search result : $it")
}
}
fun main() {
search()
}
Как видно, класс SearchUtil
принимает список целых чисел в качестве параметра. Функция searchItem
принимает на входе целое число (которое нужно найти) и возвращает результат. Кажется, все отлично. В чем же проблема?
Допустим, требуется найти элемент, который является списком строк или объектов. Ваши действия? Рассмотрим 2 возможных варианта решения.
- Создать еще один класс
SearchUtil
и функциюsearchItem
, которые примут строки или тип объекта и вернут результат. - Применить обобщения.
Очевидно, что первое решение не подходит. Оно обернется написанием избыточного кода, многие фрагменты которого будут дублироваться. В данном случае помогут обобщения.
Что такое обобщения?
Согласно официальной документации:
Обобщения — это классы, структуры, интерфейсы и методы, имеющие плейсхолдеры (параметры типов) для одного или более хранимых или применяемых типов. Класс обобщенной коллекции может использовать параметр типа как плейсхолдер для типа хранимых в нем объектов. Параметры типа выступают как типы его полей и типы параметров методов. Обобщенный метод может задействовать свой параметр типа как тип возвращаемого значения или как тип одного из его формальных параметров.
Короче говоря:
Обобщения — это гибкая система, позволяющая работать с любыми типами данных. Она снимает с вас все заботы о типах и поручает их компилятору.
Проще объяснить уже невозможно.
Применение обобщений
Перепишем ранее рассмотренный пример, используя обобщения. Для преобразования класса SearchUtil
в обобщения нужно внести в него изменения:
class SearchUtil<T>(private val list: List<T>)
T
указывает на возможность любого типа в качестве аргумента.
Кроме того, необходимо изменить функцию searchItem
:
fun searchItem(element: T, foundItem: (element: T?) -> Unit)
Теперь мы можем задействовать любой тип по желанию:
val searchUtil = SearchUtil(list = listOfObjects)
val searchUtil = SearchUtil(list = listOfNumber)
Вышеуказанный код будет работать без проблем. Рассмотрим реальный пример:
data class Person(val name: String, val email: String, val age: Int)
fun search() {
val henry = Person(name = "Henry", email = "[email protected]", age = 24)
val robert = Person(name = "Robert", email = "[email protected]", age = 22)
val tom = Person(name = "Tom", email = "[email protected]", age = 25)
val listOfPerson = listOf(henry, robert, tom)
val searchUtil = SearchUtil(list = listOfPerson)
searchUtil.searchItem(element = henry) {
println("Search result : $it")
}
}
class SearchUtil<T>(private val list: List<T>) {
fun searchItem(element: T, foundItem: (element: T?) -> Unit) {
val itemFoundList = list.filter {
it == element
}
if (itemFoundList.isNullOrEmpty()) foundItem(null) else
foundItem(itemFoundList.first())
}
}
fun main() {
search()
}
Мы создаем класс данных Person
и выполняем операцию поиска по listOfPerson
. При необходимости провести поиск по списку целых чисел мы можем сделать это без каких-либо изменений в SearchUtil
или searchItem
.
val listOfNumbers = listOf(25, 46, 35) val searchUtil = SearchUtil(list = listOfNumbers) searchUtil.searchItem(element = 25) { println("Search result : $it") }
Читайте также:
- Kotlin-реализация RecyclerView на Android
- Реактивное программирование или сопрограммы: между молотом и наковальней?
- Изменение типа с помощью typealias
Читайте нас в Telegram, VK и Яндекс.Дзен
Перевод статьи Farhan Tanvir: How to Use Generics in Kotlin