programowanieProgramista Android

Opisz mechanizm działania kolekcji w Kotlinie: różnice między List, MutableList, Set, MutableSet, Map, MutableMap. Jakie pułapki mogą wystąpić przy ich używaniu? Podaj przykłady kodu.

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

Kotlin oferuje dwa typy kolekcji: immutable (niemutable) i mutable (mutable).

  • List — niemutable lista. Nie można dodawać/usuwać elementów.
  • MutableList — mutable lista: można dodawać i usuwać elementy.
  • Set — niemutable zbiór (unikalne elementy).
  • MutableSet — mutable zbiór.
  • Map — mapa asocjacyjna (klucz-wartość), niemutable.
  • MutableMap — mutable mapa asocjacyjna.

Przykład kodu:

val fruits: List<String> = listOf("Apple", "Banana", "Cherry") val mutableFruits: MutableList<String> = mutableListOf("Apple", "Banana") mutableFruits.add("Cherry") val fruitSet: Set<String> = setOf("Apple", "Banana") // Unikalność elementów val mutableFruitSet: MutableSet<String> = mutableSetOf("Apple", "Banana") mutableFruitSet.add("Cherry") val scores: Map<String, Int> = mapOf("Tom" to 80, "Jane" to 90) val mutableScores: MutableMap<String, Int> = mutableMapOf("Tom" to 80) mutableScores["Jane"] = 90

Szczegóły:

  • Kolekcje domyślnie są niemutable.
  • Wiele funkcji zwracających listy z biblioteki standardowej zwraca List (a nie MutableList).
  • Pracując z kolekcjami, ważne jest, aby nie zmieniać tych, które nie zostały zaprojektowane do zmian.

Pytanie z pułapką.

Jeśli masz funkcję, która przyjmuje List<T> jako parametr, czy możesz w jakiś sposób zmienić tę listę wewnątrz funkcji?

Odpowiedź: Nie, jeśli parametr jest typu List<T>, to wewnątrz funkcji nie można dodać/usunąć elementów. Ale jeśli faktycznie przekazano MutableList<T>, można go przekonwertować do tego typu (co wiąże się z ryzykiem):

fun modifyList(list: List<String>) { if (list is MutableList) { list.add("Another") // Działa, jeśli oryginalna kolekcja jest mutable } }

Nie zaleca się tego, ponieważ narusza to kontrakt (List powinien być niemutable!).

Przykłady rzeczywistych błędów z powodu nieznajomości szczegółów tematu.


Historia

W dużym projekcie używano funkcji przyjmującej List<Customer>, próbując dodać do niej nowy element wewnątrz funkcji. Błąd kompilacji (add/clear/remove nie są zdefiniowane dla List) został wykryty dopiero podczas przeglądu, ponieważ wymagano właśnie mutable list do przekształcania danych.


Historia

Kolekcja została zadeklarowana jako MutableList, ale była przekazywana do kilku wątków bez synchronizacji. Ostatecznie wystąpiły konkurencyjne zmiany, prowadzące do "ConcurrentModificationException" i uszkodzenia stanu listy. Błąd był długo poszukiwany, nie uwzględniono bezpieczeństwa wątków.


Historia

W jednym z serwisów do pracy z wynikami zapytań z bazy danych używano mutableListOf, a później przekazywano referencję na zewnątrz. Zewnętrzny kod przez pomyłkę czyścił listę. W rezultacie do użytkownika docierały puste dane, ponieważ referencje nie były klonowane, a mutable kolekcje były modyfikowane poza warstwą logiki biznesowej.