Avatar ·

Как создать массив в Kotlin, указав только размер, как в Java (new int[10])?

Я только начал изучать Kotlin после Java и столкнулся с проблемой. В Java я привык создавать массивы так: ```java int[] numbers = new int[10]; String[] names = new String[5]; ``` То есть я просто указываю тип и размер, а массив заполняется значениями по умолчанию (0 для int, null для String). Это очень удобно, когда я заранее знаю, сколько элементов будет, но не знаю их конкретных значений. В Kotlin я попробовал сделать что-то похожее: ```kotlin var numbers: IntArray = IntArray(10) // Это работает, но я не уверен, что правильно var names: Array = Array(5) // А вот это выдаёт ошибку компиляции ``` Я вижу, что `IntArray(10)` вроде бы создаёт массив из 10 нулей, но синтаксис с `Array(5)` не работает. В документации я нашёл, что нужно использовать лямбду-инициализатор, но это кажется странным — зачем писать дополнительный код, если я просто хочу массив с null-значениями? Подскажите, пожалуйста, как правильно создавать массивы в Kotlin, когда нужен только размер, как в Java? Есть ли простой способ без лямбды? И в чём разница между `IntArray` и `Array`? Буду благодарен за примеры с разными типами данных (Int, String, пользовательские классы). <<>>

Основные способы создания массивов в Kotlin

В Kotlin действительно нет прямого аналога new int[10] из Java, но есть несколько эквивалентных и даже более гибких способов. Главное — понять разницу между примитивными массивами (IntArray, ByteArray и т.д.) и обобщёнными массивами (Array<T>).

1. Примитивные массивы (для чисел, boolean, char)

Для примитивных типов Kotlin предоставляет специальные классы: IntArray, ByteArray, ShortArray, LongArray, FloatArray, DoubleArray, CharArray, BooleanArray. Они работают без автоупаковки и наиболее эффективны.

// Создание массива из 10 нулей (аналог new int[10])
val numbers = IntArray(10)

// Создание массива из 5 false (аналог new boolean[5])
val flags = BooleanArray(5)

// Создание массива из 3 пустых символов '\u0000' (аналог new char[3])
val chars = CharArray(3)

// Можно указать начальное значение через лямбду:
val squares = IntArray(5) { i -> i * i } // [0, 1, 4, 9, 16]

Важно: IntArray(10) — это именно то, что вам нужно, если вы хотите массив, заполненный нулями. Компилятор Kotlin сам подставит значения по умолчанию (0 для чисел, false для boolean, '\u0000' для char).

2. Обобщённые массивы Array<T>

Для ссылочных типов (String, пользовательские классы, nullable-типы) используется класс Array<T>. Здесь обязательно нужно передать инициализатор, потому что Kotlin не может автоматически заполнить массив null для non-null типов.

// Массив строк, заполненный null (только для nullable типа)
val names: Array<String?> = arrayOfNulls(5) // [null, null, null, null, null]

// Массив строк, заполненный пустыми строками (non-null)
val words = Array(5) { "" } // ["", "", "", "", ""]

// Массив пользовательских объектов
data class Person(val name: String, val age: Int)
val people = Array(3) { Person("John", 25) } // Все три ссылки на один объект!
// Лучше создавать разные объекты:
val uniquePeople = Array(3) { Person("User$it", 20 + it) }

3. Альтернативы: списки (List) и фабричные функции

Если вам не нужен фиксированный размер, рассмотрите MutableList:

val mutableList = MutableList(10) { 0 } // Список из 10 нулей
mutableList.add(42) // Можно добавлять элементы

Или используйте фабричную функцию Array(size, init) — это стандартный способ создания массива с произвольной инициализацией:

// Массив с разными значениями:
val randomNumbers = Array(5) { Random.nextInt(100) }

Ключевые различия между IntArray и Array<Int>

  • Производительность: IntArray хранит примитивы (int), Array<Int> — объекты Integer (автоупаковка). Для больших массивов чисел IntArray в 3-5 раз быстрее и занимает меньше памяти.
  • Nullability: IntArray не может содержать null (значение по умолчанию — 0). Array<Int?> может содержать null.
  • Синтаксис: IntArray(10) без инициализатора работает. Для Array<Int>(10) нужен инициализатор, так как нет значения по умолчанию для non-null типа.

Практический пример: сравнение с Java

// Java
int[] javaArray = new int[10]; // [0,0,0,0,0,0,0,0,0,0]
String[] javaStrings = new String[5]; // [null, null, null, null, null]

// Kotlin
val kotlinInts = IntArray(10) // [0,0,0,0,0,0,0,0,0,0]
val kotlinStrings = arrayOfNulls<String>(5) // [null, null, null, null, null]
// или
val kotlinStrings2 = Array<String?>(5) { null } // то же самое

Итог: для чисел используйте IntArray(size) (или аналоги для других примитивов), для ссылочных типов — arrayOfNulls<T>(size) если нужны null, или Array(size) { defaultValue } если нужно конкретное значение.

<<>>

Альтернативный подход: использование списков (List) вместо массивов

В современном Kotlin массивы обычно используются реже, чем в Java. Рекомендуется отдавать предпочтение неизменяемым спискам (List) или изменяемым (MutableList), так как они:

  • Имеют богатый API (фильтрация, сортировка, трансформация)
  • Поддерживают дженерики без проблем с массивами
  • Не имеют проблем с ковариантностью (массивы в Kotlin инвариантны)
// Создание списка фиксированного размера с начальными значениями
val numbers: MutableList<Int> = MutableList(10) { 0 }
val names: MutableList<String?> = MutableList(5) { null }

// Можно менять элементы
numbers[3] = 42

// Преобразование в массив, если нужно
val array = numbers.toIntArray() // или toTypedArray() для ссылочных типов

Если вам действительно нужен массив (например, для работы с Java-библиотекой или критичной по производительности задачи), используйте примитивные массивы. Во всех остальных случаях списки удобнее и безопаснее.

Также стоит отметить, что в Kotlin есть функция Array(size) { index -> value }, которая позволяет гибко инициализировать элементы, что часто удобнее, чем заполнять массив после создания циклом.