Kotlin — это современный язык программирования, который компилируется в байт-код Java. Он бесплатный и с открытым исходным кодом , и обещает сделать кодирование для Android еще более увлекательным.
В предыдущей статье этой серии вы узнали об обнуляемости, циклах и условиях в Kotlin. В этом уроке мы продолжим изучать язык, рассматривая API диапазонов и коллекций в Kotlin.
1. Диапазоны
Диапазон в Kotlin — это уникальный тип, который определяет начальное значение и конечное значение. Другими словами, это интервал между начальным и конечным значением. Диапазоны в Kotlin закрыты, это означает, что начальное и конечное значение включены в диапазон.
Теперь мы рассмотрим различные способы создания диапазонов в Kotlin.
Оператор ..
1
|
val oneToFive = 1..5
|
В приведенном выше коде мы создали закрытый диапазон. Эта переменная oneToFive
будет содержать следующие значения: 1, 2, 3, 4, 5. Мы можем зациклить ее, используя конструкцию цикла for
.
1
2
3
|
for (n in oneToFive) {
print(n)
}
|
Код выше можно сократить до:
1
2
3
|
for (n in 1..5) {
print(n)
}
|
Мы также можем создать диапазон символов:
1
|
val aToZ = «a»..»z»
|
Переменная aToZ
будет иметь все буквы английского алфавита.
Функция rangeTo()
Оператор ..
можно заменить на rangeTo()
расширения rangeTo()
для создания диапазона. Например, мы также можем сделать это 1.rangeTo(5)
и он все равно будет иметь те же результаты, что и оператор ..
как обсуждалось ранее.
1
|
val oneToFive: IntRange = 1.rangeTo(5)
|
Функция downTo()
Это еще одна функция расширения, которая создает диапазон, начиная с данного числа и заканчивая другим.
1
|
val fiveToOne = 5.downTo(1)
|
Мы можем изменить диапазон, используя функцию step()
. Это изменит дельту между каждым элементом в диапазоне.
1
|
val oneToTenStep = 1..10 step 2 // 1, 3, 5, 7, 9
|
Код выше будет содержать нечетные числа от 1 до 10.
Оператор в
Оператор in
используется для определения наличия значения в данном диапазоне.
1
2
3
|
if (5 in 1..10) {
print(«Yes 5 is in the range») // prints «Yes 5 is in the range»
}
|
В приведенном выше коде мы проверили, находится ли 5 в диапазоне 1..10, используя оператор in
. Мы также можем сделать обратное, используя !n
чтобы проверить, не находится ли 5 в диапазоне.
2. Коллекции
Коллекции используются для хранения групп связанных объектов в памяти. В коллекции мы можем извлекать, хранить или упорядочивать объекты. Kotlin предоставляет API своих коллекций в качестве стандартной библиотеки, построенной на основе API Java Collections. (Мы обсудим интерфейсы в Kotlin в следующем посте.)
Следует отметить, что эти интерфейсы связаны с их реализацией во время компиляции. Вы не можете видеть исходный код реализации в Kotlin, потому что коллекции фактически реализуются стандартными коллекциями Java, такими как ArrayList
, Maps
, HashMap
, Sets
, HashSet
, List
и так далее. Чтобы действительно понять API коллекций в Kotlin, вы должны быть знакомы с этими базовыми классами и интерфейсами в Java.
В этом разделе мы узнаем о коллекциях List
, Set
и Map
в Kotlin. (Если вы хотите освежить в массивах в Kotlin, пожалуйста, посетите первый учебник в этой серии .)
Коллекции Kotlin дают нам возможность многого достичь с помощью небольшого кода — в отличие от Java, который, кажется, нуждается в большом количестве кода, чтобы чего-то достичь! У Котлина есть два варианта коллекций: изменяемые и неизменяемые. Изменяемая коллекция предоставляет нам возможность изменять коллекцию путем добавления, удаления или замены элемента. Неизменяемые коллекции не могут быть изменены и не имеют этих вспомогательных методов.
Обратите внимание, что добавление, удаление или замена элемента в неизменяемой коллекции возможны с помощью операторных функций (мы вскоре вернемся к этому), но в итоге они создадут новую коллекцию.
Iterable
интерфейс
Интерфейс Kotlin Iterable
находится на вершине иерархии классов коллекций. Этот интерфейс позволяет представлять коллекции в виде последовательности элементов (которые, естественно, могут повторяться).
1
2
3
|
public interface Iterable<out T> {
public abstract operator fun iterator(): Iterator<T>
}
|
Интерфейс Collection
Интерфейс Kotlin Collection
расширяет интерфейс Iterable
. Интерфейс Collection
является неизменным. Другими словами, у вас есть доступ только для чтения к коллекциям. Интерфейсы Set
и List
(подробнее об этом ниже) в Kotlin расширяют этот интерфейс.
Некоторые из функций и свойств, доступных в интерфейсе Collection
:
-
size
: это свойство возвращает размер коллекции. -
isEmpty()
: возвращает true, если коллекция пуста или false в противном случае. -
contains(element: E)
: возвращает true, если элемент, указанный в аргументе, присутствует в коллекции. -
containsAll(element: Collection<E>)
: возвращает true, если элемент в коллекции, переданный в качестве аргумента, присутствует в коллекции.
1
2
3
4
5
6
7
|
public interface Collection<out E> : Iterable<E> {
public val size: Int
public fun isEmpty(): Boolean
public operator fun contains(element: @UnsafeVariance E): Boolean
override fun iterator(): Iterator<E>
public fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean
}
|
MutableIterable
интерфейс
Этот интерфейс в Kotlin дает нам специализированный изменяемый итератор из родительского интерфейса Iterable
.
1
2
3
|
public interface MutableIterable<out T> : Iterable<T> {
override fun iterator(): MutableIterator<T>
}
|
Интерфейс MutableCollection
Интерфейс MutableCollection
в Kotlin — это специализированный интерфейс, который позволяет изменять коллекции. Другими словами, операции добавления и удаления могут быть выполнены для данной коллекции. Этот интерфейс расширяет как интерфейс Collection
интерфейс MutableIterable
уже рассмотренный выше. Интерфейсы MutableSet
и MutableList
(мы вскоре к ним вернемся) в Kotlin расширяют этот интерфейс. Функции, доступные в этом интерфейсе, кроме функций, доступных в его родителях:
-
add(element: E)
: добавляет элемент, переданный в качестве аргумента, в коллекцию и возвращает true в случае успеха или false, если коллекция не поддерживает дубликаты и элемент уже присутствует. -
remove(element: E)
: удаляет элемент, переданный в качестве аргумента из коллекции. Возвращает true, если успешно, или false, если его не было в коллекции. -
addAll(elements: Collection<E>)
: добавляет все элементы в коллекции, переданные в качестве аргументов в коллекцию. Возвращает true, если успешно, или false, если ничего не было добавлено. -
removeAll(elements: Collection<E>)
: удаляет все элементы, присутствующие в коллекции, переданные в качестве аргументов. Возвращает true, если успешно, или false, если ничего не было удалено. -
retainAll(elements: Collection<E>)
: сохраняет только элементы, присутствующие в коллекциях, переданных в качестве аргументов. Возвращает true, если успешно, или false, если ничего не было сохранено. -
clear()
: удаляет все элементы из этой коллекции.
1
2
3
4
5
6
7
8
9
|
public interface MutableCollection<E> : Collection<E>, MutableIterable<E> {
override fun iterator(): MutableIterator<E>
public fun add(element: E): Boolean
public fun remove(element: E): Boolean
public fun addAll(elements: Collection<E>): Boolean
public fun removeAll(elements: Collection<E>): Boolean
public fun retainAll(elements: Collection<E>): Boolean
public fun clear(): Unit
}
|
Теперь, когда вы узнали о главных интерфейсах в иерархии классов коллекций в Kotlin, давайте теперь посмотрим, как Kotlin обрабатывает коллекции, такие как списки, наборы и карты, в оставшейся части руководства.
Списки
Список — это упорядоченная коллекция элементов. Это популярная коллекция, которая широко используется. Давайте рассмотрим различные способы создания списка в Kotlin.
Использование функции listOf()
В Kotlin мы можем создать неизменный (только для чтения) список, используя вспомогательную функцию listOf()
из стандартной библиотеки Kotlin. Эта функция возвращает тип интерфейса List
Kotlin.
1
2
3
4
5
|
var numbers: List<Int> = listOf(1, 2, 3, 4, 5)
var names: List<String> = listOf(«Chike», «Nnamdi», «Mgbemena»)
for (name in names) {
println(name)
}
|
Выполнение кода выше выведет:
1
2
3
|
Chike
Nnamdi
Mgbemena
|
Более того, мы можем передавать значения различных типов в listOf()
качестве аргументов, и результат все равно будет работать — это будет список смешанного типа.
1
|
var listMixedTypes = listOf(«Chike», 1, 2.445, ‘s’) // will still compile
|
Использование функции emptyList()
Эта функция просто создает пустой неизменяемый список и возвращает тип интерфейса Kotlin List
.
1
|
val emptyList: List<String> = emptyList<String>()
|
Использование функции listOfNotNull()
Эта функция создает новый неизменный список, содержащий только те элементы, которые не равны NULL. Обратите внимание, что эта функция также возвращает тип интерфейса Kotlin List
.
1
|
val nonNullsList: List<String> = listOfNotNull(2, 45, 2, null, 5, null)
|
Интерфейс List
из стандартной библиотеки Kotlin расширяет только интерфейс Collection
. Другими словами, его единственным родителем является интерфейс Collection
. Он переопределяет все функции в родительском интерфейсе для удовлетворения его особых потребностей, а также определяет свои собственные функции, такие как:
-
get(index: Int)
: оператор функции, который возвращает элемент по указанному индексу. -
indexOf(element: E)
: возвращает индекс первого вхождения элемента, переданного в качестве аргумента в списке, или -1, если ничего не найдено. -
lastIndexOf(element: E)
: возвращает индекс последнего вхождения элемента, переданного в качестве аргумента в списке, или -1, если ничего не найдено. -
listIterator()
: возвращает итератор списка для элементов в списке. -
subList(fromIndex: Int, toIndex: Int)
: возвращает список, содержащий часть списка между указанными начальным и конечным индексами.
1
2
3
4
|
println(names.size) // 3
println(names.get(0)) // «Chike»
println(names.indexOf(«Mgbemena»)) // 2
println(names.contains(«Nnamdi»)) // ‘true’
|
Использование функции arrayListOf()
Это создает изменяемый список и возвращает тип Java ArrayList
.
1
|
val stringList: ArrayList<String> = arrayListOf<String>(«Hello», «You», «There»)
|
Использование функции mutableListOf()
Чтобы добавить, удалить или заменить значения в списке, нам нужно сделать список изменяемым. Мы можем преобразовать неизменяемый список в изменяемый, вызвав функцию toMutableList()
в списке. Однако обратите внимание, что этот метод создаст новый список.
1
2
|
var mutableNames1 = names.toMutableList()
mutableNames1.add(«Ruth») // now mutable and added «Ruth» to list
|
Чтобы создать изменяемый список определенного типа с нуля, например, String
, мы используем mutableListOf<String>()
, в то время как для смешанных типов мы можем просто использовать вместо этого функцию mutableListOf()
.
1
2
3
4
5
6
7
8
|
// a mutable list of a certain type eg String
val mutableListNames: MutableList<String> = mutableListOf<String>(«Josh», «Kene», «Sanya»)
mutableListNames.add(«Mary»)
mutableListNames.removeAt(1)
mutableListNames[0] = «Oluchi» // replaces the element in index 0 with «Oluchi»
// a mutable list of mixed types
val mutableListMixed = mutableListOf(«BMW», «Toyota», 1, 6.76, ‘v’)
|
Любая из этих функций возвращает MutableList
интерфейса MutableList
Kotlin. Этот интерфейс расширяет интерфейсы MutableCollection
и List
рассмотренные ранее в этом разделе. Интерфейс MutableList
добавляет методы для поиска или замены элемента на основе его позиции:
-
set(index: Int, element: E)
: заменяет элемент в списке другим элементом. Это возвращает элемент ранее в указанной позиции. -
add(index: Int, element: E)
: вставляет элемент по указанному индексу. -
removeAt(index: Int)
: избавляется от элемента по определенному индексу.
1
2
3
4
5
6
7
8
9
|
val mutableListFood: MutableList<String> = mutableListOf<String>(«Rice & stew», «Jollof rice», «Eba & Egusi», «Fried rice»)
mutableListFood.remove(«Fried rice»)
mutableListFood.removeAt(0)
mutableListFood.set(0, «Beans»)
mutableListFood.add(1, «Bread & tea»)
for (foodName in mutableListFood) {
println(foodName)
}
|
Запустив приведенный выше код, мы получим следующий результат:
1
2
3
|
Beans
Bread & tea
Eba & Egusi
|
Обратите внимание, что все эти функции создают Java ArrayList
за кулисами.
наборы
Набор — это неупорядоченная коллекция уникальных элементов. Другими словами, он не может иметь дубликатов! Давайте посмотрим на некоторые из различных способов создания набора в Kotlin. Каждый из них создает различную структуру данных, каждая из которых оптимизирована для определенного вида задач.
Использование функции setOf()
Чтобы создать неизменяемый (только для чтения) набор в Kotlin, мы можем использовать функцию setOf()
, которая возвращает тип интерфейса Kotlin Set
.
1
2
3
4
|
// creates a immutable set of mixed types
val mixedTypesSet = setOf(2, 4.454, «how», «far», ‘c’) // will compile
var intSet: Set<Int> = setOf(1, 3, 4) // only integers types allowed
|
Обратите внимание, что интерфейс Kotlin Set
расширяет только интерфейс Kotlin Collection
и переопределяет все свойства, доступные в его родительском элементе.
Использование функции hashSetOf()
Использование функции hashSetOf()
создает коллекцию Java HashSet
которая хранит элементы в хэш-таблице. Поскольку эта функция возвращает тип Java HashSet
, мы можем добавлять, удалять или очищать элементы в наборе. Другими словами, это изменчиво.
1
2
3
|
val intsHashSet: java.util.HashSet<Int> = hashSetOf(1, 2, 6, 3)
intsHashSet.add(5)
intsHashSet.remove(1)
|
Использование функции sortedSetOf()
Использование функции sortedSetOf()
создает TreeSet
коллекцию Java TreeSet
, которая упорядочивает элементы на основе их естественного упорядочения или компаратора. Этот набор также изменчив.
1
2
3
4
|
val intsSortedSet: java.util.TreeSet<Int> = sortedSetOf(4, 1, 7, 2)
intsSortedSet.add(6)
intsSortedSet.remove(1)
intsSortedSet.clear()
|
Использование функции linkedSetOf()
Эта функция возвращает тип Java LinkedHashSet
. Этот изменяемый набор поддерживает связанный список записей в наборе в том порядке, в котором они были вставлены.
1
2
3
4
|
val intsLinkedHashSet: java.util.LinkedHashSet<Int> = linkedSetOf(5, 2, 7, 2, 5) // 5, 2, 7
intsLinkedHashSet.add(4)
intsLinkedHashSet.remove(2)
intsLinkedHashSet.clear()
|
Использование функции mutableSetOf()
Мы можем использовать mutableSetOf()
для создания изменяемого набора. Эта функция возвращает MutableSet
интерфейса Kotlin MutableSet
. За кулисами эта функция просто создает Java LinkedHashSet
.
1
2
3
4
|
// creates a mutable set of int types only
val intsMutableSet: MutableSet<Int> = mutableSetOf(3, 5, 6, 2, 0)
intsMutableSet.add(8)
intsMutableSet.remove(3)
|
Интерфейс MutableSet
расширяет интерфейсы MutableCollection
и Set
.
Карты
Карты ассоциируют ключи со значениями. Ключи должны быть уникальными, но связанные значения не должны быть. Таким образом, каждый ключ можно использовать для уникальной идентификации связанного значения, поскольку карта гарантирует, что в коллекции не будет дублированных ключей. За кулисами Kotlin использует коллекцию Java Map
для реализации своего типа коллекции карт.
Использование функции mapOf()
Чтобы создать неизменяемый или доступный только для чтения набор Map
в Kotlin, мы используем mapOf()
. Мы создаем карту с этой функцией, предоставляя ей список пар — первое значение — это ключ, а второе — это значение. Вызов этой функции возвращает тип интерфейса Kotlin Map
.
1
2
3
4
5
|
val callingCodesMap: Map<Int, String> = mapOf(234 to «Nigeria», 1 to «USA», 233 to «Ghana»)
for ((key, value) in callingCodesMap) {
println(«$key is the calling code for $value»)
}
print(callingCodesMap[234]) // Nigeria
|
Выполнение приведенного выше кода даст результат:
1
2
3
|
234 is the calling code for Nigeria
1 is the calling code for USA
233 is the calling code for Ghana
|
В отличие от интерфейсов List
и Set
в Kotlin, которые расширяют интерфейс Collection
интерфейс Map
вообще не расширяется. Некоторые из свойств и функций, доступных в этом интерфейсе:
-
size
: это свойство возвращает размер коллекции карт. -
isEmpty()
: возвращает true, если карта пуста или false в противном случае. -
containsKey(key: K)
: возвращает true, если карта содержит ключ в аргументе. -
containsValue(value: V)
: возвращает true, если карта отображает один или несколько ключей на значение, переданное в качестве аргумента. -
get(key: K)
: возвращает значение, соответствующее данному ключу, или ‘null’, если ничего не найдено. -
keys
: это свойство возвращает неизменныйSet
всех ключей на карте. -
values
: возвращает неизменнуюCollection
всех значений на карте.
Использование функции mutableMapOf()
Функция mutableMapOf()
создает для нас изменяемую карту, чтобы мы могли добавлять и удалять элементы в карте. Это возвращает MutableMap
интерфейса Kotlin MutableMap
.
1
2
3
4
5
|
val currenciesMutableMap: MutableMap<String, String> = mutableMapOf(«Naira» to «Nigeria», «Dollars» to «USA», «Pounds» to «UK»)
println(«Countries are ${currenciesMutableMap.values}») // Countries are [Nigeria, USA, UK]
println(«Currencies are ${currenciesMutableMap.keys}») // Currencies are [Naira, Dollars, Pounds]
currenciesMutableMap.put(«Cedi», «Ghana»)
currenciesMutableMap.remove(«Dollars»)
|
Интерфейс MutableMap
не расширяет интерфейс MutableCollection
; это единственный родительский интерфейс Map
. Он переопределяет keys
, entries
и values
свойств из родительского интерфейса, чтобы переопределить их. Вот некоторые из дополнительных функций, доступных в интерфейсе MutableMap
:
-
put(key: K, value: V)
: вставляет пару ключ-значение в карту. Это вернет предыдущее значение, связанное с ключом, или ноль, если ключ ранее не использовался. -
remove(key: K)
: удаляет ключ и его связанное значение с карты. -
putAll
(from: Map<out K, V>)
: обновляет карту со всеми данными с данной карты. Будут добавлены новые ключи, а существующие ключи будут обновлены с новыми значениями. -
clear()
: удаляет все элементы с карты.
Мы можем получить значение для ключа, используя функцию get()
. Мы также можем использовать квадратную скобку в качестве ярлыка для get()
.
1
2
|
print(currenciesMutableMap.get(«Nigeria»)) // will print Naira
print(currenciesMutableMap[«Nigeria»]) // will print Naira
|
Использование функции hashMapOf()
Использование этой функции возвращает тип Java HashMap
который является изменяемым. Класс HashMap
использует хеш-таблицу для реализации интерфейса Java Map
.
1
2
3
4
|
val personsHashMap: java.util.HashMap<Int, String> = hashMapOf(1 to «Chike», 2 to «John», 3 to «Emeka»)
personsHashMap.put(4, «Chuka»)
personsHashMap.remove(2)
print(personsHashMap[1]) // will print Chike
|
Использование функции linkedHashMap()
Эта функция возвращает тип Java LinkedHashMap
который является изменяемым. Класс LinkedHashMap
расширяет Java HashMap
и поддерживает связанный список записей на карте в том порядке, в котором они были вставлены.
1
2
3
4
5
|
val postalCodesHashMap: java.util.LinkedHashMap<String, String> =
linkedMapOf(«NG» to «Nigeria»,»AU» to «Australia»,»CA» to «Canada»)
postalCodesHashMap.put(«NA», «Namibia»)
postalCodesHashMap.remove(«AU»)
postalCodesHashMap.get(«CA») // Canada
|
Использование функции sortedMapOf()
Эта функция возвращает тип Java SortedMap
который является изменяемым. Класс Java SortedMap
видит, что записи на карте поддерживаются в порядке возрастания ключа.
1
2
3
|
val personsSortedMap: java.util.SortedMap<Int, String> = sortedMapOf(2 to «Chike», 1 to «John», 3 to «Emeka»)
personsSortedMap.put(7, «Adam»)
personsSortedMap.remove(3)
|
Помните, что реализация этих коллекционных интерфейсов в Kotlin происходит во время компиляции.
Функции работы с коллекциями
Kotlin предоставляет нам много полезных операторных функций, называемых функциями расширения, которые можно вызывать в коллекциях. Давайте посмотрим на некоторые из самых полезных.
last()
функция
Эта операторная функция возвращает последний элемент в коллекции, такой как список или набор. Мы также можем предоставить предикат для поиска в подмножестве элементов.
1
2
3
4
5
6
7
8
|
val stringList: List<String> = listOf(«in», «the», «club»)
print(stringList.last()) // will print «club»
// given a predicate
print(stringList.last{ it.length == 3}) // will print «the»
val intSet: Set<Int> = setOf(3, 5, 6, 6, 6, 3)
print(intSet.last()) // will print 6
|
first()
функция
Эта операторная функция возвращает первый элемент при вызове в коллекции, такой как список или набор. Если указан предикат, он использует предикат, чтобы ограничить операцию подмножеством элементов.
1
2
|
print(stringList.first()) // will print «in»
print(intSet.first()) // will print 3
|
max()
функция
Вызов этой операторной функции в коллекции, такой как список или набор, возвращает наибольший элемент, или ноль, если наибольший элемент не найден.
1
2
3
|
val intList: List<Int> = listOf(1, 3, 4)
print(intList.max()) // will print 4
print(intSet.max()) // will print 6
|
Функция drop()
Вызов этой операторной функции возвращает новый список или набор, содержащий все элементы, кроме первых n элементов.
1
|
print(stringList.drop(2)) // will print «club»
|
Функция plus()
Эта операторная функция возвращает коллекцию, содержащую все элементы оригинала, а затем данный элемент, если его еще нет в коллекции. В результате будет создан новый список вместо изменения списка.
1
|
print(intList.plus(6)) // will print [1, 3, 4, 6]
|
Функция minus()
Противоположностью функции plus()
является функция minus()
. Возвращает коллекцию, содержащую все элементы исходного набора, кроме данного элемента. Это также заканчивает тем, что создает новый список вместо того, чтобы изменять список.
1
|
print(intList.minus(3)) // will print [1, 4]
|
average()
функция
Вызов этой операторной функции вернет среднее количество элементов в коллекции.
1
|
print(intList.average()) // will print 2.6666666666666665
|
Большинство из этих функций расширения доступны в стандартной библиотеке коллекций Kotlin . Вам рекомендуется ознакомиться с документацией, чтобы узнать о других.
Вывод
В этом уроке вы узнали об API диапазона и коллекций на языке программирования Kotlin. В следующем уроке из серии Kotlin From Scratch вы познакомитесь с функциями в Kotlin. До скорого!
Чтобы узнать больше о языке Kotlin, я рекомендую посетить документацию Kotlin . Или посмотрите некоторые другие наши посты по разработке приложений для Android здесь на Envato Tuts!
-
Android SDKВведение в компоненты архитектуры Android
-
Машинное обучениеСоздание интеллектуальных чат-ботов на Android с IBM Watson
-
Android SDKJava против Kotlin: стоит ли использовать Kotlin для разработки под Android?
-
Android SDKСовет: пишите более чистый код с помощью Kotlin SAM Conversions
-
Android SDKAndroid O: проверка номера телефона с помощью SMS-токенов