La bibliothèque standard de Kotlin fournit un ensemble complet d’outils de gestion collections – des groupes d’un nombre variable d’éléments (éventuellement zéro) qui partagent une signification pour le problème à résoudre et sont exploités en commun.
Les collections sont un concept courant pour la plupart des langages de programmation, donc si vous connaissez, par exemple, les collections Java ou Python, vous pouvez ignorer cette introduction et passer aux sections détaillées.
Une collection contient généralement un certain nombre d’objets (ce nombre peut également être zéro) du même type. Les objets d’une collection sont appelés éléments ou éléments. Par exemple, tous les étudiants d’un département forment une collection qui permet de calculer leur âge moyen. Les types de collecte suivants sont pertinents pour Kotlin :
- Lister est une collection ordonnée avec accès aux éléments par des indices – des nombres entiers qui reflètent leur position. Les éléments peuvent apparaître plusieurs fois dans une liste. Un exemple de liste est une phrase : c’est un groupe de mots, leur ordre est important, et ils peuvent se répéter.
- Régler est une collection d’éléments uniques. Il reflète l’abstraction mathématique de l’ensemble : un groupe d’objets sans répétitions. Généralement, l’ordre des éléments d’ensemble n’a aucune signification. Par exemple, un alphabet est un ensemble de lettres.
- Carte (ou dictionnaire) est un ensemble de paires clé-valeur. Les clés sont uniques et chacune d’elles correspond exactement à une valeur. Les valeurs peuvent être des doublons. Les cartes sont utiles pour stocker des connexions logiques entre des objets, par exemple, l’ID d’un employé et son poste.
Kotlin vous permet de manipuler des collections indépendamment du type exact d’objets qui y sont stockés. En d’autres termes, vous ajoutez un String
à une liste de String
C’est de la même manière que vous le feriez avec Int
s ou une classe définie par l’utilisateur. Ainsi, la bibliothèque standard de Kotlin propose des interfaces, des classes et des fonctions génériques pour créer, remplir et gérer des collections de tout type.
Les interfaces de collection et les fonctions associées se trouvent dans le package kotlin.collections. Faisons un tour d’horizon de son contenu.
Types de collecte
La bibliothèque standard de Kotlin fournit des implémentations pour les types de collections de base : ensembles, listes et cartes. Une paire d’interfaces représente chaque type de collection :
- UNE lecture seulement interface qui fournit des opérations pour accéder aux éléments de collection.
- UNE mutable interface qui étend l’interface en lecture seule correspondante avec des opérations d’écriture : ajout, suppression et mise à jour de ses éléments.
Notez que la modification d’une collection mutable n’exige pas qu’elle soit une var
: les opérations d’écriture modifient le même objet de collection mutable, de sorte que la référence ne change pas. Bien que, si vous essayez de réaffecter un val
collection, vous obtiendrez une erreur de compilation.
fun main() { //sampleStart val numbers = mutableListOf("one", "two", "three", "four") numbers.add("five") // this is OK //numbers = mutableListOf("six", "seven") // compilation error //sampleEnd }
Les types de collection en lecture seule sont covariants. Cela signifie que, si un Rectangle
la classe hérite de Shape
, vous pouvez utiliser un List<Rectangle>
n’importe où le List<Shape>
est requis. En d’autres termes, les types de collection ont la même relation de sous-typage que les types d’élément. Les mappages sont covariants sur le type de valeur, mais pas sur le type de clé.
À leur tour, les collections mutables ne sont pas covariantes ; sinon, cela conduirait à des échecs d’exécution. Si MutableList<Rectangle>
était un sous-type de MutableList<Shape>
, vous pouvez insérer d’autres Shape
héritiers (par exemple, Circle
) en elle, violant ainsi son Rectangle
type argument.
Vous trouverez ci-dessous un schéma des interfaces de la collection Kotlin :
Parcourons les interfaces et leurs implémentations.
Collection
Collection<T>
est la racine de la hiérarchie de collection. Cette interface représente le comportement courant d’une collection en lecture seule : récupération de la taille, vérification de l’appartenance à un élément, etc. Collection
hérite de la Iterable<T>
interface qui définit les opérations d’itération des éléments. Vous pouvez utiliser Collection
en tant que paramètre d’une fonction qui s’applique à différents types de collection. Pour des cas plus spécifiques, utilisez le Collection
héritiers de : List
et Set
.
fun printAll(strings: Collection<String>) { for(s in strings) print("$s ") println() } fun main() { val stringList = listOf("one", "two", "one") printAll(stringList) val stringSet = setOf("one", "two", "three") printAll(stringSet) }
MutableCollection
est un Collection
avec des opérations d’écriture, telles que add
et remove
.
fun List<String>.getShortWordsTo(shortWords: MutableList<String>, maxLength: Int) { this.filterTo(shortWords) { it.length <= maxLength } // throwing away the articles val articles = setOf("a", "A", "an", "An", "the", "The") shortWords -= articles } fun main() { val words = "A long time ago in a galaxy far far away".split(" ") val shortWords = mutableListOf<String>() words.getShortWordsTo(shortWords, 3) println(shortWords) }
Lister
List<T>
stocke les éléments dans un ordre spécifié et leur fournit un accès indexé. Les indices partent de zéro – l’indice du premier élément – et vont à lastIndex
qui est le (list.size - 1)
.
fun main() { //sampleStart val numbers = listOf("one", "two", "three", "four") println("Number of elements: ${numbers.size}") println("Third element: ${numbers.get(2)}") println("Fourth element: ${numbers[3]}") println("Index of element "two" ${numbers.indexOf("two")}") //sampleEnd }
Les éléments de liste (y compris les valeurs NULL) peuvent dupliquer : une liste peut contenir un nombre quelconque d’objets égaux ou d’occurrences d’un seul objet. Deux listes sont considérées comme égales si elles ont les mêmes tailles et des éléments structurellement égaux aux mêmes positions.
data class Person(var name: String, var age: Int) fun main() { //sampleStart val bob = Person("Bob", 31) val people = listOf(Person("Adam", 20), bob, bob) val people2 = listOf(Person("Adam", 20), Person("Bob", 31), bob) println(people == people2) bob.age = 32 println(people == people2) //sampleEnd }
MutableList<T>
est un List
avec des opérations d’écriture spécifiques à une liste, par exemple, pour ajouter ou supprimer un élément à une position spécifique.
fun main() { //sampleStart val numbers = mutableListOf(1, 2, 3, 4) numbers.add(5) numbers.removeAt(1) numbers[0] = 0 numbers.shuffle() println(numbers) //sampleEnd }
Comme vous le voyez, à certains égards, les listes sont très similaires aux tableaux. Cependant, il y a une différence importante : la taille d’un tableau est définie lors de l’initialisation et n’est jamais modifiée ; à son tour, une liste n’a pas de taille prédéfinie ; la taille d’une liste peut être modifiée à la suite d’opérations d’écriture : ajout, mise à jour ou suppression d’éléments.
Dans Kotlin, l’implémentation par défaut de List
est ArrayList
que vous pouvez considérer comme un tableau redimensionnable.
Régler
Set<T>
stocke des éléments uniques ; leur ordre est généralement indéfini. null
les éléments sont également uniques : un Set
ne peut contenir qu’un null
. Deux ensembles sont égaux s’ils ont la même taille, et pour chaque élément d’un ensemble, il y a un élément égal dans l’autre ensemble.
fun main() { //sampleStart val numbers = setOf(1, 2, 3, 4) println("Number of elements: ${numbers.size}") if (numbers.contains(1)) println("1 is in the set") val numbersBackwards = setOf(4, 3, 2, 1) println("The sets are equal: ${numbers == numbersBackwards}") //sampleEnd }
MutableSet
est un Set
avec les opérations d’écriture de MutableCollection
.
L’implémentation par défaut de Set
– LinkedHashSet
– préserve l’ordre d’insertion des éléments. Par conséquent, les fonctions qui reposent sur l’ordre, telles que first()
ou last()
, renvoient des résultats prévisibles sur de tels ensembles.
fun main() { //sampleStart val numbers = setOf(1, 2, 3, 4) // LinkedHashSet is the default implementation val numbersBackwards = setOf(4, 3, 2, 1) println(numbers.first() == numbersBackwards.first()) println(numbers.first() == numbersBackwards.last()) //sampleEnd }
Une implémentation alternative – HashSet
– ne dit rien sur l’ordre des éléments, donc appeler de telles fonctions dessus renvoie des résultats imprévisibles. Cependant, HashSet
nécessite moins de mémoire pour stocker le même nombre d’éléments.
Carte
Map<K, V>
n’est pas héritier de la Collection
interface; Cependant, il s’agit également d’un type de collection Kotlin. UNE Map
magasins valeur clé paires (ou entrées); les clés sont uniques, mais différentes clés peuvent être associées à des valeurs égales. Les Map
L’interface fournit des fonctions spécifiques, telles que l’accès à la valeur par clé, la recherche de clés et de valeurs, etc.
fun main() { //sampleStart val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1) println("All keys: ${numbersMap.keys}") println("All values: ${numbersMap.values}") if ("key2" in numbersMap) println("Value by key "key2": ${numbersMap["key2"]}") if (1 in numbersMap.values) println("The value 1 is in the map") if (numbersMap.containsValue(1)) println("The value 1 is in the map") // same as previous //sampleEnd }
Deux cartes contenant les paires égales sont égales quel que soit l’ordre des paires.
fun main() { //sampleStart val numbersMap = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key4" to 1) val anotherMap = mapOf("key2" to 2, "key1" to 1, "key4" to 1, "key3" to 3) println("The maps are equal: ${numbersMap == anotherMap}") //sampleEnd }
MutableMap
est un Map
avec les opérations d’écriture de carte, par exemple, vous pouvez ajouter une nouvelle paire clé-valeur ou mettre à jour la valeur associée à la clé donnée.
fun main() { //sampleStart val numbersMap = mutableMapOf("one" to 1, "two" to 2) numbersMap.put("three", 3) numbersMap["one"] = 11 println(numbersMap) //sampleEnd }
L’implémentation par défaut de Map
– LinkedHashMap
– préserve l’ordre d’insertion des éléments lors de l’itération de la carte. À son tour, une mise en œuvre alternative – HashMap
– ne dit rien sur l’ordre des éléments.