JavaRush /Курсы /Kotlin SELF /Массивы в Kotlin: Array и IntArray

Массивы в Kotlin: Array и IntArray

Kotlin SELF
7 уровень , 1 лекция
Открыта

1. Зачем нужны массивы

Когда вы только начинаете программировать, кажется, что переменные можно плодить бесконечно: score1, score2, score3… и всё будет нормально. Но реальность быстро напоминает: программист — не бухгалтер с калькулятором, и хранить “список однотипных вещей” в десятках отдельных переменных — это путь к хаосу, ошибкам и печали.

Представьте задачу: хранить шаги за неделю, или оценки за 10 контрольных, или температуру по дням. Если делать это отдельными переменными, вы сразу сталкиваетесь с тремя проблемами: неудобно перебирать значения циклом, неудобно передавать “набор” в функции, неудобно расширять логику. Нам нужна структура, которая держит “много одинаковых по смыслу данных” под одним именем. Этой структурой и будет массив.

В программировании очень полезно смотреть на вещи под разными углами. Когда вы видите 7 значений (например, по дням недели), вы можете думать так: “это семь отдельных чисел”. А можете думать так: “это один набор данных, у которого есть размер и элементы”. Массив как раз заставляет мозг везде видеть набор однотипных вещей.

Давайте представим, как выглядел бы трекер тренировок без массивов. Это было бы что-то вроде:

fun main() {
    val mon = 0
    val tue = 30
    val wed = 0
    val thu = 45
    val fri = 0
    val sat = 60
    val sun = 15

    println("Monday minutes = $mon") // Monday minutes = 0
}

Работает? Да. Удобно? Уже не очень. А если потом нужно “пройтись циклом по дням” и вывести все значения? А если нужно найти максимум? А если нужно заменить “7 дней” на “30 дней” (условно)? Вот тут массивы начинают выигрывать с разгромным счётом.

Что такое массив

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

Удобная бытовая аналогия: массив — это коробка с пронумерованными ячейками. Коробка уже сделана на заводе, и количество ячеек не меняется. Вы можете перекладывать содержимое ячеек, можете смотреть, что лежит в конкретной ячейке, можете пройтись по всем ячейкам по порядку — но “вставить ещё одну ячейку между 3 и 4” нельзя. “Коробка” не поддерживает расширение.

Слово “фиксированный” хочется подчеркнуть ещё раз, потому что это один из самых частых источников удивления. Массив нельзя “расширить” так, как расширяют список дел на бумаге: дописал пункт — и всё. Если у массива 7 элементов, то “восьмой” туда не поместится. Это фундаментальное свойство массивов: размер задаётся при создании и не меняется.

На практике это означает: если вам внезапно понадобилось больше мест, вы создаёте новый массив и переносите данные. Это звучит страшновато, но позже мы научимся делать это более удобно. Сегодня достаточно запомнить правило: массив — это “фиксированная коробка”, а не “резиновый пакет”.

2. Виды массивов в Kotlin: Array и IntArray

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

  • Array<T> — универсальный массив для больших объектов (например, String и любые классы).
  • примитивные массивы (IntArray, DoubleArray, CharArray и т.д.) — оптимизированные для чисел/символов без лишних накладных расходов.

Array<T>: универсальный массив

Главный “универсальный” массив Kotlin — это Array<T>. Он подходит для хранения объектов: строк, любых классов (а потом, когда появятся свои типы — и их тоже). Тип элемента пишется в угловых скобках: Array<String>, Array<Int>, Array<Char>.

Самый простой способ создать такой массив — arrayOf(...): вы перечисляете элементы, Kotlin собирает из них массив.

Пример: массив строк через arrayOf(...)

fun main() {
    val names: Array<String> = arrayOf("Ann", "Bob", "Cindy")
    println("names size = ${names.size}") // names size = 3
}

Здесь сразу появляется новое важное свойство: size. Это количество элементов массива. Оно пригодится сразу, потому что все границы массива зависят от его размера.

Пример: Kotlin часто сам выводит тип

fun main() {
    val colors = arrayOf("red", "green", "blue")
    println("colors size = ${colors.size}") // colors size = 3
}

Мы не написали Array<String> — и всё равно получилось правильно, потому что Kotlin вывел тип по значениям. Это удобно, но на первых порах полезно иногда писать тип явно, чтобы мозг привыкал читать код “слева направо”.

Примитивные массивы: IntArray, DoubleArray, CharArray

На этом месте почти все новички задают логичный вопрос: “Почему нельзя всегда использовать Array<T>? Зачем вообще ещё какие-то IntArray, DoubleArray?”

Ответ — можно использовать и Array<T>, но в Kotlin специально добавили отдельные массивы для примитивных типов: IntArray, DoubleArray, CharArray и т.д. Язык Java, на основе которого создавался Kotlin, позволяет очень компактно упаковывать примитивные типы в массивы.

Элементы в примитивных массивах упакованы более плотно, чем в Array<T>. И за счёт этой оптимизации занимают меньше места и работают быстрее. Просто запомните правило: для целых чисел в базовых задачах берите IntArray, для DoubleDoubleArray, для символов — CharArray. Так проще читать код и меньше неожиданностей. Kotlin прямо выделяет такие “примитивные массивы” как отдельные типы.

Сравним “в лоб”:

Что храним Универсальный массив Примитивный массив
Строки
Array<String>
(нет отдельного)
Целые
Array<Int>
IntArray
Дробные
Array<Double>
DoubleArray
Символы
Array<Char>
CharArray

Важно: IntArray — это не Array<Int>. Они похожи в использовании (есть size, можно перебирать циклом), но это разные типы.

Пример: массив целых через intArrayOf(...)

fun main() {
    val scores: IntArray = intArrayOf(10, 20, 30)
    println("scores size = ${scores.size}") // scores size = 3
}

4. Создание массива нужного размера и значения по умолчанию

До этого мы создавали массивы, когда уже знаем конкретные элементы. Но в реальных задачах часто наоборот: мы знаем сколько элементов надо, а значения появятся позже (например, пользователь введёт 7 чисел, по одному на день недели). Для этого у примитивных массивов есть конструктор вида IntArray(size).

И тут важный момент: массив будет заполнен значениями по умолчанию. Для Int это 0.

Пример: создаём массив на 5 элементов, заполненный нулями

fun main() {
    val zeros = IntArray(5)
    println("zeros size = ${zeros.size}") // zeros size = 5

    for (x in zeros) {
        print("$x ")
    }
    // 0 0 0 0 0
}

Обратите внимание на for (x in zeros): мы перебираем элементы массива “по значениям”. Мы пока не работаем с индексами (это будет следующая лекция), но уже можем увидеть содержимое.

5. Мини-приложение: трекер тренировок за неделю

Чтобы массивы были не “в вакууме”, начнём собирать маленькое консольное приложение, которое будем развивать дальше по курсу. Идея простая: мы хотим хранить данные по тренировкам за неделю. Пока без ввода, без редактирования, без статистики — только заготовка структуры. Да, это очень похоже на реальную разработку: сначала делаем каркас, потом наполняем логикой.

В первой версии мы заведём:

  1. массив названий дней недели (строки),
  2. массив минут тренировки по каждому дню (целые числа),
  3. выведем, сколько у нас дней в данных, чтобы убедиться, что структура собралась.

Пример: каркас данных (дни + минуты)

fun main() {
    val days: Array<String> = arrayOf("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")
    val minutes: IntArray = intArrayOf(0, 30, 0, 45, 0, 60, 15)

    println("Days count = ${days.size}")       // Days count = 7
    println("Minutes count = ${minutes.size}") // Minutes count = 7
}

Пока это выглядит как “просто два массива”, но тут уже видна важная мысль: данные одной природы должны храниться вместе. Мы не делаем monMinutes, tueMinutes, wedMinutes — мы делаем один массив minutes, где каждая позиция соответствует дню недели.

И ещё важный момент: если у вас два массива, которые “идут параллельно” (день и минуты), их размеры должны совпадать. Иначе логика начнёт ломаться, а отладка превратится в археологическую экспедицию по вашему коду.

6. Типичные ошибки при работе с массивами

Ошибка №1: ожидать, что массив “сам расширится”.
Новички иногда думают: “ну я же могу присвоить a[10] = 5, значит массив станет больше”. Нет: размер фиксирован, и попытка обратиться за пределы приведёт к ошибке во время выполнения. Запоминаем мантру дня: массив — коробка фиксированного размера.

Ошибка №2: путать Array<Int> и IntArray и удивляться, почему Kotlin не принимает одно вместо другого.
Это разные типы. В базовых задачах по целым числам выбирайте IntArray: так проще читать код и меньше шансов запутаться. Kotlin отдельно описывает примитивные массивы как самостоятельные классы.

Ошибка №3: создать IntArray(n) и ожидать “случайные значения” или “пустоту”.
IntArray(n) заполняется нулями, потому что Kotlin гарантирует предсказуемое начальное состояние. Это удобно, но если вы ожидали другое — обязательно делайте отдельный шаг заполнения (мы займёмся этим в следующих лекциях).

Ошибка №4: делать массив из “всего подряд”, смешивая типы.
Массив любит порядок: один массив — один тип. Если вам кажется, что “очень хочется смешать”, чаще всего это сигнал, что данные нужно хранить по-другому (но это уже разговор не сегодняшнего дня). Сейчас держимся простого правила: Array<String> для строк, IntArray для целых.

Ошибка №5: забывать проверять здравый смысл размеров параллельных массивов.
Если у вас два массива, которые должны быть синхронны (например, days и minutes), они обязаны иметь одинаковый size. Иначе вы потом получите “день есть, минут нет” — почти как абонемент в спортзал, но без спортзала.

1
Задача
Kotlin SELF, 7 уровень, 1 лекция
Недоступна
Витрина магазина
Витрина магазина
1
Задача
Kotlin SELF, 7 уровень, 1 лекция
Недоступна
Пустой буфер
Пустой буфер
1
Задача
Kotlin SELF, 7 уровень, 1 лекция
Недоступна
Заготовка под список
Заготовка под список
1
Задача
Kotlin SELF, 7 уровень, 1 лекция
Недоступна
Данные недели
Данные недели
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ