Spec-Zone.ru › Kotlin 2

Коллекции в Java и Kotlin

Коллекции — это группы переменного числа элементов (возможно, нулевого), которые имеют значение для решаемой задачи и обычно используются вместе. В этом руководстве объясняются и сравниваются понятия и операции с коллекциями в Java и Kotlin. Оно поможет вам перейти с Java на Kotlin и писать код в истинно котлиновском стиле.

Первая часть этого руководства содержит краткий словарь операций над одинаковыми коллекциями в Java и Kotlin. Она разделена на одинаковые операции и операции, существующие только в Kotlin. Во второй части руководства, начиная с раздела Изменяемость, некоторые различия объясняются на конкретных примерах.

Введение в коллекции см. в разделе Обзор коллекций или в этом видео Себастьяна Айгнера, представителя разработчиков Kotlin.

Во всех приведённых ниже примерах используются только API стандартных библиотек Java и Kotlin.

Одинаковые операции в Java и Kotlin

В Kotlin многие операции с коллекциями выглядят точно так же, как их аналоги в Java.

Операции со списками, множествами, очередями и двусторонними очередями

Описание

Общие операции

Другие варианты в Kotlin

Добавить один или несколько элементов

add(), addAll()

Используйте оператор plusAssign (+=): collection += element, collection += anotherCollection.

Проверить, содержит ли коллекция один или несколько элементов

contains(), containsAll()

Используйте ключевое слово in, чтобы вызвать contains() в форме оператора: element in collection.

Проверить, пуста ли коллекция

isEmpty()

Используйте isNotEmpty(), чтобы проверить, что коллекция не пуста.

Удалить элементы по заданному условию

removeIf()

Оставить только выбранные элементы

retainAll()

Удалить все элементы из коллекции

clear()

Получить поток из коллекции

stream()

В Kotlin есть собственный способ обработки потоков: последовательности и такие методы, как map() и filter().

Получить итератор коллекции

iterator()

Операции с отображениями

Описание

Общие операции

Другие варианты в Kotlin

Добавить один или несколько элементов

put(), putAll(), putIfAbsent()

В Kotlin присваивание map[key] = value ведёт себя так же, как put(key, value). Кроме того, можно использовать оператор plusAssign (+=): map += Pair(key, value) или map += anotherMap.

Заменить один или несколько элементов

put(), replace(), replaceAll()

Используйте оператор индексирования map[key] = value вместо put() и replace().

Получить элемент

get()

Чтобы получить элемент, используйте оператор индексирования: map[index].

Проверить, содержит ли отображение один или несколько элементов

containsKey(), containsValue()

Используйте ключевое слово in, чтобы вызвать contains() в форме оператора: element in map.

Проверить, пусто ли отображение

isEmpty()

Используйте isNotEmpty(), чтобы проверить, что отображение не пусто.

Удалить элемент

remove(key), remove(key, value)

Используйте оператор minusAssign (-=): map -= key.

Удалить все элементы из отображения

clear()

Получить поток из отображения

stream() для записей, ключей или значений

Операции, существующие только для списков

Описание

Общие операции

Другие варианты в Kotlin

Получить индекс элемента

indexOf()

Получить последний индекс элемента

lastIndexOf()

Получить элемент

get()

Чтобы получить элемент, используйте оператор индексирования: list[index].

Получить подсписок

subList()

Заменить один или несколько элементов

set(), replaceAll()

Используйте оператор индексирования вместо set(): list[index] = value.

Операции, которые немного различаются

Операции для любых типов коллекций

Описание

Java

Kotlin

Получить размер коллекции

size()

count(), size

Получить плоский доступ к элементам вложенной коллекции

collectionOfCollections.forEach(flatCollection::addAll) или collectionOfCollections.stream().flatMap().collect()

flatten() или flatMap()

Применить заданную функцию к каждому элементу

stream().map().collect()

map()

Последовательно применить заданную операцию к элементам коллекции и вернуть накопленный результат

stream().reduce()

reduce(), fold()

Сгруппировать элементы по классификатору и подсчитать их

stream().collect(Collectors.groupingBy(classifier, counting()))

eachCount()

Отфильтровать по условию

stream().filter().collect()

filter()

Проверить, удовлетворяют ли элементы коллекции условию

stream().noneMatch(), stream().anyMatch(), stream().allMatch()

none(), any(), all()

Отсортировать элементы

stream().sorted().collect()

sorted()

Взять первые N элементов

stream().limit(N).collect()

take(N)

Взять элементы, удовлетворяющие предикату

stream().takeWhile().collect()

takeWhile()

Пропустить первые N элементов

stream().skip(N).collect()

drop(N)

Пропустить элементы, удовлетворяющие предикату

stream().dropWhile().collect()

dropWhile()

Создать отображения из элементов коллекции и связанных с ними значений

stream().collect(toMap(keyMapper, valueMapper))

associate()

Чтобы выполнить все перечисленные выше операции с отображениями, сначала нужно получить entrySet отображения.

Операции со списками

Описание

Java

Kotlin

Отсортировать список в естественном порядке

sort(null)

sort()

Отсортировать список в порядке убывания

sort(comparator)

sortDescending()

Удалить элемент из списка

remove(index), remove(element)

removeAt(index), remove(element) или collection -= element

Заполнить все элементы списка заданным значением

Collections.fill()

fill()

Получить уникальные элементы списка

stream().distinct().toList()

distinct()

Операции, отсутствующие в стандартной библиотеке Java

  • zip(), unzip() — преобразовать коллекцию.

  • aggregate() — сгруппировать по условию.

  • takeLast(), takeLastWhile(), dropLast(), dropLastWhile() — взять или пропустить элементы по предикату.

  • slice(), chunked(), windowed() — получить части коллекции.

  • Операторы plus (+) и minus (-) — добавить или удалить элементы.

Если вы хотите подробно изучить zip(), chunked(), windowed() и некоторые другие операции, посмотрите это видео Себастьяна Айгнера о расширенных операциях с коллекциями в Kotlin:

Изменяемость

В Java существуют изменяемые коллекции:

// Java
// This list is mutable!
public List<Customer> getCustomers() { ... }

Частично изменяемые коллекции:

// Java
List<String> numbers = Arrays.asList("one", "two", "three", "four");
numbers.add("five"); // Fails in runtime with `UnsupportedOperationException`

А также неизменяемые коллекции:

// Java
List<String> numbers = new LinkedList<>();
// This list is immutable!
List<String> immutableCollection = Collections.unmodifiableList(numbers);
immutableCollection.add("five"); // Fails in runtime with `UnsupportedOperationException`

Если написать два последних фрагмента кода в IntelliJ IDEA, среда разработки предупредит, что вы пытаетесь изменить неизменяемый объект. Этот код скомпилируется, но завершится с ошибкой во время выполнения с UnsupportedOperationException. По типу коллекции нельзя определить, является ли она изменяемой.

В отличие от Java, в Kotlin вы явно объявляете изменяемые или доступные только для чтения коллекции в зависимости от своих потребностей. Если попытаться изменить коллекцию, доступную только для чтения, код не скомпилируется:

// Kotlin
val numbers = mutableListOf("one", "two", "three", "four")
numbers.add("five")            // This is OK
val immutableNumbers = listOf("one", "two")
//immutableNumbers.add("five") // Compilation error - Unresolved reference: add

Подробнее о неизменяемости см. на странице соглашений по написанию кода Kotlin.

Ковариантность

В Java нельзя передать коллекцию с типом-потомком функции, которая принимает коллекцию с типом-предком. Например, если Rectangle наследуется от Shape, нельзя передать коллекцию элементов типа Rectangle функции, которая принимает коллекцию элементов типа Shape. Чтобы код скомпилировался, используйте тип ? extends Shape, чтобы функция могла принимать коллекции с любыми наследниками Shape:

// Java
class Shape {}

class Rectangle extends Shape {}

public void doSthWithShapes(List<? extends Shape> shapes) {
/* If using just List<Shape>, the code won't compile when calling
this function with the List<Rectangle> as the argument as below */
}

public void main() {
    var rectangles = List.of(new Rectangle(), new Rectangle());
    doSthWithShapes(rectangles);
}

В Kotlin типы коллекций, доступных только для чтения, ковариантны. Это означает, что если класс Rectangle наследуется от класса Shape, тип List<Rectangle> можно использовать везде, где требуется тип List<Shape>. Иными словами, отношения подтипов между типами коллекций совпадают с отношениями между типами элементов. Отображения ковариантны по типу значения, но не по типу ключа. Изменяемые коллекции не ковариантны — это привело бы к ошибкам во время выполнения.

// Kotlin
open class Shape(val name: String)

class Rectangle(private val rectangleName: String) : Shape(rectangleName)

fun doSthWithShapes(shapes: List<Shape>) {
    println("The shapes are: ${shapes.joinToString { it.name }}")
}

fun main() {
    val rectangles = listOf(Rectangle("rhombus"), Rectangle("parallelepiped"))
    doSthWithShapes(rectangles)
}

Подробнее о типах коллекций читайте здесь.

Диапазоны и прогрессии

В Kotlin можно создавать интервалы с помощью диапазонов. Например, Version(1, 11)..Version(1, 30) включает все версии от 1.11 до 1.30. Проверить, входит ли ваша версия в диапазон, можно с помощью оператора in: Version(0, 9) in versionRange.

В Java нужно вручную проверять, попадает ли Version в заданные границы:

// Java
class Version implements Comparable<Version> {

    int major;
    int minor;

    Version(int major, int minor) {
        this.major = major;
        this.minor = minor;
    }

    @Override
    public int compareTo(Version o) {
        if (this.major != o.major) {
            return this.major - o.major;
        }
        return this.minor - o.minor;
    }
}

public void compareVersions() {
    var minVersion = new Version(1, 11);
    var maxVersion = new Version(1, 31);

   System.out.println(
           versionIsInRange(new Version(0, 9), minVersion, maxVersion));
   System.out.println(
           versionIsInRange(new Version(1, 20), minVersion, maxVersion));
}

public Boolean versionIsInRange(Version versionToCheck, Version minVersion, 
                                Version maxVersion) {
    return versionToCheck.compareTo(minVersion) >= 0 
            && versionToCheck.compareTo(maxVersion) <= 0;
}

В Kotlin диапазон используется как единый объект. Не нужно создавать две переменные и сравнивать с ними Version:

// Kotlin
class Version(val major: Int, val minor: Int): Comparable<Version> {
    override fun compareTo(other: Version): Int {
        if (this.major != other.major) {
            return this.major - other.major
        }
        return this.minor - other.minor
    }
}

fun main() {
    val versionRange = Version(1, 11)..Version(1, 30)

    println(Version(0, 9) in versionRange)
    println(Version(1, 20) in versionRange)
}

Если требуется исключить одну из границ, например проверить, что версия больше или равна (>=) минимальной версии и меньше (<) максимальной, включительные диапазоны не подойдут.

Сравнение по нескольким критериям

В Java для сравнения объектов по нескольким критериям можно использовать функции comparing() и thenComparingX() интерфейса Comparator. Например, для сравнения людей по имени и возрасту:

class Person implements Comparable<Person> {
    String name;
    int age;

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return this.name + " " + age;
    }
}

public void comparePersons() {
    var persons = List.of(new Person("Jack", 35), new Person("David", 30), 
            new Person("Jack", 25));
    System.out.println(persons.stream().sorted(Comparator
            .comparing(Person::getName)
            .thenComparingInt(Person::getAge)).collect(toList()));
}

В Kotlin достаточно перечислить поля, по которым нужно выполнить сравнение:

data class Person(
    val name: String,
    val age: Int
)

fun main() {
    val persons = listOf(Person("Jack", 35), Person("David", 30), 
        Person("Jack", 25))
    println(persons.sortedWith(compareBy(Person::name, Person::age)))
}

Последовательности

В Java последовательность чисел можно сгенерировать так:

// Java
int sum = IntStream.iterate(1, e -> e + 3)
    .limit(10).sum();
System.out.println(sum); // Prints 145

В Kotlin используйте последовательности. Многоэтапная обработка последовательностей по возможности выполняется лениво: фактические вычисления происходят только при запросе результата всей цепочки обработки.

fun main() {
//sampleStart
    // Kotlin
    val sum = generateSequence(1) {
        it + 3
    }.take(10).sum()
    println(sum) // Prints 145
//sampleEnd
}

Последовательности могут уменьшить число шагов, необходимых для выполнения некоторых операций фильтрации. См. пример обработки последовательности, который показывает различие между Iterable и Sequence.

Удаление элементов из списка

В Java функция remove() принимает индекс удаляемого элемента.

При удалении целочисленного элемента передайте функцию Integer.valueOf() в качестве аргумента функции remove():

// Java
public void remove() {
    var numbers = new ArrayList<>();
    numbers.add(1);
    numbers.add(2);
    numbers.add(3);
    numbers.add(1);
    numbers.remove(1); // This removes by index
    System.out.println(numbers); // [1, 3, 1]
    numbers.remove(Integer.valueOf(1));
    System.out.println(numbers); // [3, 1]
}

В Kotlin есть два способа удаления элемента: по индексу с помощью removeAt() и по значению с помощью remove().

fun main() {
//sampleStart
    // Kotlin
    val numbers = mutableListOf(1, 2, 3, 1)
    numbers.removeAt(0)
    println(numbers) // [2, 3, 1]
    numbers.remove(1)
    println(numbers) // [2, 3]
//sampleEnd
}

Обход отображения

В Java можно обойти отображение с помощью forEach:

// Java
numbers.forEach((k,v) -> System.out.println("Key = " + k + ", Value = " + v));

В Kotlin для обхода отображения используйте цикл for или forEach, аналогичный forEach в Java:

// Kotlin
for ((k, v) in numbers) {
    println("Key = $k, Value = $v")
}
// Or
numbers.forEach { (k, v) -> println("Key = $k, Value = $v") }

Получение первого и последнего элементов, возможно, пустой коллекции

В Java безопасно получить первый и последний элементы можно, проверив размер коллекции и используя индексы:

// Java
var list = new ArrayList<>();
//...
if (list.size() > 0) {
    System.out.println(list.get(0));
    System.out.println(list.get(list.size() - 1));
}

В JDK 21 и более поздних версиях можно также использовать методы getFirst() и getLast(), доступные во всех реализациях SequencedCollection. Сюда входят все реализации List, а также другие коллекции, например LinkedHashSet. Например, для ArrayList:

// Java
var list = new ArrayList<>();
//...
if (!list.isEmpty()) {
    System.out.println(list.getFirst());
    System.out.println(list.getLast());
}

В Kotlin есть специальные функции firstOrNull() и lastOrNull(). С помощью Elvis operator можно сразу выполнить дальнейшие действия в зависимости от результата функции. Например, firstOrNull():

// Kotlin
val emails = listOf<String>() // Might be empty
val theOldestEmail = emails.firstOrNull() ?: ""
val theFreshestEmail = emails.lastOrNull() ?: ""

Создание множества из списка

В Java для создания Set из List можно использовать функцию Set.copyOf:

// Java
public void listToSet() {
    var sourceList = List.of(1, 2, 3, 1);
    var copySet = Set.copyOf(sourceList);
    System.out.println(copySet);
}

В Kotlin используйте функцию toSet():

fun main() {
//sampleStart
    // Kotlin
    val sourceList = listOf(1, 2, 3, 1)
    val copySet = sourceList.toSet()
    println(copySet)
//sampleEnd
}

Группировка элементов

В Java можно группировать элементы с помощью функции Collectors groupingBy():

// Java
public void analyzeLogs() {
    var requests = List.of(
        new Request("https://kotlinlang.org/docs/home.html", 200),
        new Request("https://kotlinlang.org/docs/home.html", 400),
        new Request("https://kotlinlang.org/docs/comparison-to-java.html", 200)
    );
    var urlsAndRequests = requests.stream().collect(
            Collectors.groupingBy(Request::getUrl));
    System.out.println(urlsAndRequests);
}

В Kotlin используйте функцию groupBy():

data class Request(
    val url: String,
    val responseCode: Int
)

fun main() {
//sampleStart
    // Kotlin
    val requests = listOf(
        Request("https://kotlinlang.org/docs/home.html", 200),
        Request("https://kotlinlang.org/docs/home.html", 400),
        Request("https://kotlinlang.org/docs/comparison-to-java.html", 200)
    )
    println(requests.groupBy(Request::url))
//sampleEnd
}

Фильтрация элементов

В Java для фильтрации элементов коллекции нужно использовать Stream API. В Stream API есть операции intermediate и terminal. filter() — промежуточная операция, которая возвращает поток. Чтобы получить коллекцию в качестве результата, нужно использовать терминальную операцию, например collect(). Например, чтобы оставить только те пары, ключи которых заканчиваются на 1, а значения больше 10:

// Java
public void filterEndsWith() {
    var numbers = Map.of("key1", 1, "key2", 2, "key3", 3, "key11", 11);
    var filteredNumbers = numbers.entrySet().stream()
        .filter(entry -> entry.getKey().endsWith("1") && entry.getValue() > 10)
        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
    System.out.println(filteredNumbers);
}

В Kotlin фильтрация встроена в коллекции, а filter() возвращает коллекцию того же типа, что и исходная. Поэтому достаточно указать filter() и предикат:

fun main() {
//sampleStart
    // Kotlin
    val numbers = mapOf("key1" to 1, "key2" to 2, "key3" to 3, "key11" to 11)
    val filteredNumbers = numbers.filter { (key, value) -> key.endsWith("1") && value > 10 }
    println(filteredNumbers)
//sampleEnd
}

Подробнее о фильтрации map.

Фильтрация элементов по типу

В Java, чтобы отфильтровать элементы по типу и выполнить над ними действия, нужно проверить их тип с помощью оператора instanceof, а затем выполнить приведение типа:

// Java
public void objectIsInstance() {
    var numbers = new ArrayList<>();
    numbers.add(null);
    numbers.add(1);
    numbers.add("two");
    numbers.add(3.0);
    numbers.add("four");
    System.out.println("All String elements in upper case:");
    numbers.stream().filter(it -> it instanceof String)
        .forEach( it -> System.out.println(((String) it).toUpperCase()));
}

В Kotlin достаточно вызвать filterIsInstance<NEEDED_TYPE>() для коллекции, а приведение типа выполнит механизм умных приведений типов:

// Kotlin
fun main() {
//sampleStart
    // Kotlin
    val numbers = listOf(null, 1, "two", 3.0, "four")
    println("All String elements in upper case:")
    numbers.filterIsInstance<String>().forEach {
        println(it.uppercase())
    }
//sampleEnd
}

Проверка предикатов

В некоторых задачах нужно проверить, удовлетворяют ли условию все элементы, ни один элемент или хотя бы один элемент. В Java все эти проверки можно выполнить с помощью функций Stream API allMatch(), noneMatch() и anyMatch():

// Java
public void testPredicates() {
    var numbers = List.of("one", "two", "three", "four");
    System.out.println(numbers.stream().noneMatch(it -> it.endsWith("e"))); // false
    System.out.println(numbers.stream().anyMatch(it -> it.endsWith("e"))); // true
    System.out.println(numbers.stream().allMatch(it -> it.endsWith("e"))); // false
}

В Kotlin функции-расширения none(), any() и all() доступны для любого объекта Iterable:

fun main() {
//sampleStart
// Kotlin
    val numbers = listOf("one", "two", "three", "four")
    println(numbers.none { it.endsWith("e") })
    println(numbers.any { it.endsWith("e") })
    println(numbers.all { it.endsWith("e") })
//sampleEnd
}

Подробнее о проверке предикатов.

Операции преобразования коллекций

Объединение элементов в пары

В Java можно создать пары из элементов, занимающих одинаковые позиции в двух коллекциях, перебирая их одновременно:

// Java
public void zip() {
    var colors = List.of("red", "brown");
    var animals = List.of("fox", "bear", "wolf");

    for (int i = 0; i < Math.min(colors.size(), animals.size()); i++) {
        String animal = animals.get(i);
        System.out.println("The " + animal.substring(0, 1).toUpperCase()
               + animal.substring(1) + " is " + colors.get(i));
   }
}

Если нужно сделать что-то сложнее, чем просто вывести пары элементов, можно использовать Records. В приведённом выше примере запись называлась бы record AnimalDescription(String animal, String color) {}.

В Kotlin для этого используется функция zip():

fun main() {
//sampleStart
    // Kotlin
    val colors = listOf("red", "brown")
    val animals = listOf("fox", "bear", "wolf")

    println(colors.zip(animals) { color, animal -> 
        "The ${animal.replaceFirstChar { it.uppercase() }} is $color" })
//sampleEnd
}

zip() возвращает список объектов Pair.

Если коллекции имеют разный размер, результат zip() будет соответствовать размеру меньшей коллекции. Последние элементы большей коллекции в результат не включаются.

Связывание элементов

В Java для связывания элементов с характеристиками можно использовать Stream API:

// Java
public void associate() {
    var numbers = List.of("one", "two", "three", "four");
    var wordAndLength = numbers.stream()
        .collect(toMap(number -> number, String::length));
    System.out.println(wordAndLength);
}

В Kotlin используется функция associate():

fun main() {
//sampleStart
    // Kotlin
    val numbers = listOf("one", "two", "three", "four")
    println(numbers.associateWith { it.length })
//sampleEnd
}

Что дальше?

  • Посетите раздел Kotlin Koans — выполните упражнения, чтобы изучить синтаксис Kotlin. Каждое упражнение оформлено как модульный тест, который изначально завершается с ошибкой. Ваша задача — сделать так, чтобы он прошёл.

  • Ознакомьтесь с другими идиомами Kotlin.

  • Узнайте, как преобразовать существующий код Java в Kotlin с помощью конвертера Java в Kotlin.

  • Познакомьтесь с коллекциями в Kotlin.

Если у вас есть любимая идиома, поделитесь ею, отправив pull request.

12 августа 2026 г.
Строки в Java и KotlinОбработка null в Java и Kotlin

© 2010–2026 JetBrains s.r.o. and Kotlin Programming Language contributors
Licensed under the Apache License, Version 2.0.
https://kotlinlang.org/docs/java-to-kotlin-collections-guide.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API