- Массивы и Cписки в Kotlin — Полное Руководство
- Массивы в Kotlin
- Что такое массив?
- Когда лучше использовать массивы?
- Создание массивов в Kotlin
- Массивы примитивных типов IntArray, FloatArray, DoubleArray
- Constructing collections
- Create with collection builder functions
- Empty collections
- Initializer functions for lists
- Concrete type constructors
- Copy
- Invoke functions on other collections
- Создание коллекций
- Пустая коллекция
- Функция-инициализатор для списков
- Конструкторы конкретных типов
- Копирование коллекции
- Вызов вспомогательных функций
Массивы и Cписки в Kotlin — Полное Руководство
Коллекции представляют собой гибкие «контейнеры», которые позволяют хранить вместе любое количество значений. Двумя самыми популярными типами коллекций являются массивы и списки.
Массивы в Kotlin
Массив в Kotlin соответствует базовому типу массива в Java. Массивы являются типизированными, как обычные переменные и константы, и они могут хранить много значений.
Перед созданием первого массива давайте подробнее рассмотрим, что из себя представляет массив и зачем он используется.
Что такое массив?
Массив является упорядоченной коллекцией значений одного типа. У элементов в массиве нулевая индексация. Это означает, что индекс первого элемента равен 0, индекс второго элемента равен 1 и так далее. Зная это, вы можете определить, что индекс последнего элемента будет на 1 меньше общего числа значений в массиве.
В данном массиве пять элементов с индексами от 0 до 4.
Все его значения имеют тип String , поэтому в массив, содержащий только строки, нельзя добавить значения другого типы кроме строк . Обратите внимание, что одно и то же значение может встречаться несколько раз.
Когда лучше использовать массивы?
Массивы пригодятся при необходимости хранить элементы в определенном порядке. Элементы можно будет отсортировать или сделать их выборку по индексу без итерации по всему массиву.
К примеру, при хранении данных о спортивных рекордах, порядок очень важен. Наивысший балл должен быть первым в списке (его индекс 0), далее идет второй лучший балл и так далее.
Создание массивов в Kotlin
Самым простым способом создания нового массива является использование функции arrayOf() из стандартной библиотеки Kotlin. Таким образом можно быстро указать какие значения должен хранить массив.
Поскольку данный массив содержит только целые числа, Kotlin воспринимает evenNumbers как массив значений типа Int . Этот тип записывается как Array . Тип внутри угловых скобок определяет тип значений, которые может хранить массив. Именно тип компилятор будет использовать при добавлении элементов в массив.
Если вы попытаетесь добавить строку в массиве в котором только числа, то компилятор вернет ошибку, и код не скомпилируется. Такой синтаксис для типа массива является примером аргумента типа или дженерики, о котором вы узнаете подробнее в следующем уроке.
Также, возможно создать массив, у которого все значения будут значениями по умолчанию:
Подробнее о таком синтаксисе < 5 >мы поговорим в уроке о лямбдах.
Как и с любым другим типом, лучше объявлять массивы, которые не будут меняться, то есть как константы. Рассмотрим следующий массив:
Константа vowels является массивом из строк, значения которых изменить нельзя. Это правильно, потому что список гласных букв уже давно не менялся.
Массивы примитивных типов IntArray, FloatArray, DoubleArray
При использовании функции arrayOf() и создании массивов с типами вроде Array итоговый массив представляет собой список из объектов. В частности, если вы работаете в JVM, целочисленный тип будет упакован как класс Integer , а не как примитивный тип int . Использование примитивных типов по сравнению с их упакованными аналогами в виде классов потребляет меньше памяти и приводит к повышению производительности. К сожалению, вы не можете использовать примитивы со списками (которые рассматриваются в следующем разделе), поэтому решение, стоит ли это делать, нужно принимать для каждого отдельного случая.
Стандартная библиотека Kotlin содержит и другие функции, не только arrayOf() , которые позволяют создавать массивы, соответствующие массивам примитивных типов. К примеру, вы можете создать массив нечетных чисел следующим образом:
Constructing collections
The most common way to create a collection is with the standard library functions listOf() , setOf() , mutableListOf() , mutableSetOf() . If you provide a comma-separated list of collection elements as arguments, the compiler detects the element type automatically. When creating empty collections, specify the type explicitly.
The same is available for maps with the functions mapOf() and mutableMapOf() . The map’s keys and values are passed as Pair objects (usually created with to infix function).
Note that the to notation creates a short-living Pair object, so it’s recommended that you use it only if performance isn’t critical. To avoid excessive memory usage, use alternative ways. For example, you can create a mutable map and populate it using the write operations. The apply() function can help to keep the initialization fluent here.
Create with collection builder functions
Another way of creating a collection is to call a builder function – buildList() , buildSet() , or buildMap() . They create a new, mutable collection of the corresponding type, populate it using write operations, and return a read-only collection with the same elements:
val map = buildMap < // this is MutableMap, types of key and value are inferred from the `put()` calls below put("a", 1) put("b", 0) put("c", 4) > println(map) //
Empty collections
There are also functions for creating collections without any elements: emptyList() , emptySet() , and emptyMap() . When creating empty collections, you should specify the type of elements that the collection will hold.
Initializer functions for lists
For lists, there is a constructor-like function that takes the list size and the initializer function that defines the element value based on its index.
fun main() < //sampleStart val doubled = List(3, < it * 2 >) // or MutableList if you want to change its content later println(doubled) //sampleEnd >
Concrete type constructors
To create a concrete type collection, such as an ArrayList or LinkedList , you can use the available constructors for these types. Similar constructors are available for implementations of Set and Map .
Copy
To create a collection with the same elements as an existing collection, you can use copying functions. Collection copying functions from the standard library create shallow copy collections with references to the same elements. Thus, a change made to a collection element reflects in all its copies.
Collection copying functions, such as toList() , toMutableList() , toSet() and others, create a snapshot of a collection at a specific moment. Their result is a new collection of the same elements. If you add or remove elements from the original collection, this won’t affect the copies. Copies may be changed independently of the source as well.
These functions can also be used for converting collections to other types, for example, build a set from a list or vice versa.
Alternatively, you can create new references to the same collection instance. New references are created when you initialize a collection variable with an existing collection. So, when the collection instance is altered through a reference, the changes are reflected in all its references.
Collection initialization can be used for restricting mutability. For example, if you create a List reference to a MutableList , the compiler will produce errors if you try to modify the collection through this reference.
fun main() < //sampleStart val sourceList = mutableListOf(1, 2, 3) val referenceList: List
Invoke functions on other collections
Collections can be created as a result of various operations on other collections. For example, filtering a list creates a new list of elements that match the filter:
Mapping produces a list from a transformation’s results:
For more information about operations on collections in Kotlin, see Collection operations overview.
Создание коллекций
()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/list-of.html), [`setOf ()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/set-of.html), [`mutableListOf ()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/mutable-list-of.html), [`mutableSetOf ()`](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/mutable-set-of.html). If you provide a comma-separated list of collection elements as arguments, the compiler detects the element type automatically. When creating empty collections, specify the type explicitly. —>
Самый распространённый способ создать коллекцию — использовать функции listOf() , setOf() , mutableListOf() , mutableSetOf() . Этим функциям в качестве аргументов можно передать элементы, разделяя их запятой. В этом случае тип коллекции указывать не обязательно — компилятор сам его определит. Если же вы хотите создать пустую коллекцию, то её тип необходимо указывать явно.
val numbersSet = setOf("one", "two", "three", "four") val emptySet = mutableSetOf()
Таким же образом создаются и ассоциативные списки — при помощи функций mapOf() и mutableMapOf() . Ключи и значения ассоциативного списка передаются как объекты Pair (обычно создаются с помощью инфиксной функции to ).
val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1)
Обратите внимание, что нотация to создаёт недолговечный объект Pair , поэтому рекомендуется использовать его только в том случае, если производительность не критична. Чтобы избежать чрезмерного использования памяти, используйте альтернативные способы. Например, вы можете создать MutableMap и заполнить его с помощью операций записи. Функция apply() поможет создать плавную инициализацию.
val numbersMap = mutableMapOf() .apply
Пустая коллекция
Существуют функции для создания пустых коллекций: emptyList() , emptySet() и emptyMap() . При создании пустой коллекции вы должны явно указывать тип элементов, которые будет содержать коллекция.
Функция-инициализатор для списков
У списков есть конструктор, принимающий размер списка и функцию-инициализатор, которая определяет значение элементов на основе их индексов.
fun main() < val doubled = List(3, < it * 2 >) // или MutableList, если вы хотите изменять содержимое println(doubled) // [0, 2, 4] >
Конструкторы конкретных типов
Чтобы создать коллекцию конкретного типа, например, ArrayList или LinkedList , вы можете использовать их конструкторы. Аналогичные конструкторы доступны и для реализаций Set и Map .
val linkedList = LinkedList(listOf("one", "two", "three")) val presizedSet = HashSet(32)
Копирование коллекции
Если вам требуется создать новую коллекцию, но с элементами из существующей коллекции, то вы можете её скопировать. Операции копирования из стандартной библиотеки создают неполные копии коллекций — со ссылками на исходные элементы. Поэтому изменение, внесённое в элемент коллекции, будет применено ко всем его копиям.
Функции копирования коллекций, такие как toList() , toMutableList() , toSet() и другие, фиксируют состояние коллекции в определённый момент времени. Результат их выполнения — новая коллекция, но с элементами из исходной коллекции. Если вы добавите или удалите элементы из исходной коллекции, это не повлияет на копии. Копии также могут быть изменены независимо от источника.
fun main() < val sourceList = mutableListOf(1, 2, 3) val copyList = sourceList.toMutableList() val readOnlyCopyList = sourceList.toList() sourceList.add(4) println("Copy size: $") // 3 //readOnlyCopyList.add(4) // ошибка компиляции println("Read-only copy size: $") // 3 >
Эти функции также можно использовать для преобразования типа коллекции, например, для создания множества из списка или наоборот.
В качестве альтернативы вы можете создать новую ссылку на тот же экземпляр коллекции. Новую ссылку можно создать, инициализировав новую переменную для коллекции и записав в нее существующую коллекцию. Однако, изменив новую коллекцию, изменения отразятся во всех ссылках на эту коллекцию.
Подобная инициализация может использоваться для того, чтобы ограничить доступ на изменение коллекции. Например, вы создаёте ссылку List на основе MutableList , если вы попытаетесь изменить коллекцию с помощью этой ссылки, то компилятор выдаст ошибку.
fun main() < val sourceList = mutableListOf(1, 2, 3) val referenceList: List= sourceList //referenceList.add(4) // ошибка компиляции sourceList.add(4) println(referenceList) // показывает текущее состояние sourceList - [1, 2, 3, 4] >
Вызов вспомогательных функций
Коллекции могут создаваться в результате выполнения операций над другими коллекциями. Например, функция filter создаёт новый список элементов, соответствующих заданному фильтру:
fun main() < val numbers = listOf("one", "two", "three", "four") val longerThan3 = numbers.filter < it.length >3 > println(longerThan3) // [three, four] >
Существуют функции, которые преобразуют исходные элементы и возвращают новый список с результатом. Например, функция map :
fun main() < val numbers = setOf(1, 2, 3) println(numbers.map < it * 3 >) // [3, 6, 9] println(numbers.mapIndexed < idx, value ->value * idx >) // [0, 2, 6] >
Или функция associateWith() , которая создаёт ассоциативный список:
Более подробная информация о таких функциях находится в разделе Операции коллекций.