Array<Int> di JVM menyimpan setiap elemen sebagai objek Integer. Untuk koleksi kecil ini tidak masalah, tetapi pada data besar atau operasi yang sering dijalankan (hot path), overhead alokasi objek menjadi nyata. Kotlin menyediakan kelas-kelas array primitif yang menyimpan nilai tanpa boxing. Pada chapter ini kita akan mempelajari IntArray, LongArray, DoubleArray, dan kawan-kawannya, serta kapan kita perlu memilihnya.

Kelas Array Primitif #

Kotlin menyediakan delapan kelas array primitif, satu untuk setiap tipe primitif JVM:

Tipe KotlinTipe Primitif JVMKonstruktorInisialisasi default
IntArrayintintArrayOf(...) / IntArray(n)0
LongArraylonglongArrayOf(...) / LongArray(n)0L
DoubleArraydoubledoubleArrayOf(...) / DoubleArray(n)0.0
FloatArrayfloatfloatArrayOf(...) / FloatArray(n)0.0f
ByteArraybytebyteArrayOf(...) / ByteArray(n)0
ShortArrayshortshortArrayOf(...) / ShortArray(n)0
CharArraycharcharArrayOf(...) / CharArray(n)'\u0000'
BooleanArraybooleanbooleanArrayOf(...) / BooleanArray(n)false

Setiap kelas adalah tipe berbeda — IntArray tidak mewarisi Array<Int>. Mereka juga tidak mengimplementasi Array<T>, tetapi memiliki API mirip: arr[i], arr.size, iterasi for, dan withIndex().

Mengapa Menghindari Boxing #

Boxing adalah proses membungkus nilai primitif menjadi objek. Pada Array<Int>, setiap elemen adalah referensi ke objek Integer di heap. Implikasinya:

  • Memori lebih besar — objek Integer sekitar 16 byte vs 4 byte untuk int.
  • Alokasi lebih sering — menyebabkan tekanan pada garbage collector.
  • Indirection tambahan — akses nilai harus melalui pointer.

Pada IntArray, nilai disimpan sebagai array int JNI kontigu, sama seperti int[] Java. Untuk data besar (jutaan elemen) atau operasi yang sering dijalankan, bedanya bisa menjadi signifikan.

Contoh Lengkap #

kotlin
fun main() {
    // Array primitif: tanpa boxing
    val ints: IntArray = intArrayOf(1, 2, 3, 4, 5)
    val longs: LongArray = longArrayOf(10L, 20L, 30L)
    val doubles: DoubleArray = doubleArrayOf(1.5, 2.5, 3.5)
    val bytes: ByteArray = byteArrayOf(1, 2, 3, 4)
    val shorts: ShortArray = shortArrayOf(100, 200, 300)
    val floats: FloatArray = floatArrayOf(1.0f, 2.0f, 3.0f)
    val chars: CharArray = charArrayOf('a', 'b', 'c')
    val bools: BooleanArray = booleanArrayOf(true, false, true)

    println("IntArray: ${ints.toList()}")
    println("LongArray: ${longs.toList()}")
    println("DoubleArray: ${doubles.toList()}")
    println("ByteArray: ${bytes.toList()}")
    println("ShortArray: ${shorts.toList()}")
    println("FloatArray: ${floats.toList()}")
    println("CharArray: ${chars.toList()}")
    println("BooleanArray: ${bools.toList()}")

    // Konstruktor dengan ukuran + inisialisasi lambda
    val kuadrat = IntArray(5) { i -> i * i }
    println("Kuadrat: ${kuadrat.toList()}")

    // IntArray dengan semua elemen 0
    val nol = IntArray(3)
    println("Default IntArray(3): ${nol.toList()}")

    // Akses dan modifikasi
    ints[0] = 99
    println("ints setelah [0] = 99: ${ints.toList()}")

    // size, iterasi
    println("Size: ${ints.size}")
    var total = 0
    for (v in ints) total += v
    println("Jumlah: $total")

    // Konversi: IntArray ke Array<Int> (boxed)
    val boxed: Array<Int> = ints.toTypedArray()
    println("Boxed: ${boxed.toList()}")

    // Konversi: Array<Int> ke IntArray
    val unboxed: IntArray = boxed.toIntArray()
    println("Unboxed: ${unboxed.toList()}")

    // Konversi: IntArray ke List<Int>
    val list: List<Int> = ints.toList()
    println("Sebagai List: $list")

    // Perbandingan alokasi memori (ilustrasi)
    println("IntArray elemen 1..5 = ${ints.size} elemen primitif (tanpa objek)")
    println("Array<Int> elemen 1..5 = ${boxed.size} objek Integer terpisah")
}

Output yang Dihasilkan:

text
IntArray: [1, 2, 3, 4, 5]
LongArray: [10, 20, 30]
DoubleArray: [1.5, 2.5, 3.5]
ByteArray: [1, 2, 3, 4]
ShortArray: [100, 200, 300]
FloatArray: [1.0, 2.0, 3.0]
CharArray: [a, b, c]
BooleanArray: [true, false, true]
Kuadrat: [0, 1, 4, 9, 16]
Default IntArray(3): [0, 0, 0]
ints setelah [0] = 99: [99, 2, 3, 4, 5]
Size: 5
Jumlah: 113
Boxed: [99, 2, 3, 4, 5]
Unboxed: [99, 2, 3, 4, 5]
Sebagai List: [99, 2, 3, 4, 5]
IntArray elemen 1..5 = 5 elemen primitif (tanpa objek)
Array<Int> elemen 1..5 = 5 objek Integer terpisah

Mari kita bedah baris-baris penting di atas:

  1. intArrayOf(1, 2, 3, 4, 5): membuat IntArray dari nilai literal. Tidak ada objek Integer yang dialokasikan — semua nilai disimpan sebagai int primitif dalam array kontigu.
  2. IntArray(5) { i -> i * i }: konstruktor ukuran dengan lambda inisialisasi. Lambda dipanggil sekali per indeks untuk mengisi nilai awal. Hasilnya [0, 1, 4, 9, 16].
  3. IntArray(3): konstruktor ukuran tanpa lambda. Setiap elemen diisi nilai default tipe primitif, yaitu 0 untuk IntArray.
  4. ints.toTypedArray(): konversi IntArray → Array<Int>. Operasi ini melakukan boxing setiap elemen sehingga tidak boleh dilakukan pada hot path.
  5. boxed.toIntArray(): konversi balik Array<Int> → IntArray. Berguna ketika menerima data dari API Java berbasis Integer[] dan ingin memproses secara primitif.

Operasi yang Didukung #

Meskipun bukan turunan Array<T> atau Collection<T>, array primitif mendukung sebagian besar operasi yang sama:

kotlin Contoh: operasi IntArray
val a = intArrayOf(3, 1, 4, 1, 5)
a.size                       // 5
a[2]                        // 4
a.toList()                  // List<Int>
a.sortedArray()             // IntArray baru terurut
a.sum()                     // 14
a.average()                 // 2.8
a.minOrNull()               // 1
a.maxOrNull()               // 5
a.map { it * 2 }            // List<Int> [6, 2, 8, 2, 10]
a.filter { it > 1 }         // List<Int> [3, 4, 5]

Operasi map, filter, dan sorted mengembalikan List<Int>, bukan IntArray. Untuk mempertahankan sifat primitif sepanjang pipeline, gunakan asSequence() (dibahas pada chapter Sequences) lalu kembalikan ke IntArray di akhir melalui toIntArray() pada hasil toList().

Kapan Memilih Array Primitif #

Pilih array primitif ketika:

  • Bekerja dengan koleksi besar (> 10.000 elemen) berisi tipe primitif.
  • Operasi sangat sering dijalankan (hot path): simulasi numerik, pemrosesan gambar, agregasi data streaming.
  • Berinteraksi dengan API Java yang menerima int[], long[], atau byte[].

Referensi Lanjutan #

Setelah memahami array primitif, kita akan membandingkan Array dengan List untuk menentukan pilihan yang tepat pada situasi konkret.