Salah satu kemudahan utama Kotlin dibandingkan Java adalah kita dapat menulis function, property, dan class langsung pada level file tanpa membungkusnya dalam class pembungkus. Hal ini disebut file-level declaration atau top-level declaration. Pada chapter ini kita akan memahami apa saja yang dapat dideklarasikan di top-level, konvensi penamaan file, dan bagaimana kompilator mengelola deklarasi tersebut pada bytecode JVM.

Apa yang Bisa Dideklarasikan di Top-Level #

Kotlin mengizinkan beberapa jenis deklarasi pada level file:

JenisContohKeterangan
Functionfun hitungPajak(...)Sering dipakai untuk utility dan helper.
Propertyval NAMA_APLIKASI = "..."Konstanta atau nilai konfigurasi global.
Mutable propertyvar jumlahTransaksi = 0Hati-hati: shared state.
Class / Interfaceclass Transaksi(...)Setara dengan class Java, tapi tanpa paksaan satu class per file.
Objectobject BukuBesar { ... }Singleton top-level.
Type aliastypealias DaftarTugas = List<Tugas>Memberi nama alternatif untuk tipe.
Extension functionfun String.hanyaAngka(): StringMemperluas tipe tanpa subclass.

Contoh Kode #

Kode berikut memperlihatkan beragam deklarasi top-level dalam satu file:

kotlin
// File: file_level_declarations.kt
// Mendemonstrasikan deklarasi top-level: function, property, class, dan constant.
package com.example.berkas

import kotlin.math.abs

// Top-level function — tidak perlu class pembungkus.
fun hitungPajak(nilai: Long, tarif: Double): Long {
    val pajak = (nilai * tarif).toLong()
    return pajak
}

// Top-level property — dapat diakses dari file lain dalam paket yang sama.
val NAMA_APLIKASI: String = "Kasir Sederhana"

// Top-level constant — nilai tetap di-inline pada saat kompilasi.
const val VERSI: String = "1.0.0"

// Top-level mutable property — gunakan dengan hati-hati.
var jumlahTransaksi: Int = 0

// Top-level class.
data class Transaksi(val id: Long, val nominal: Long, val keterangan: String)

// Top-level object singleton.
object BukuBesar {
    private val daftar: MutableList<Transaksi> = mutableListOf()

    fun catat(transaksi: Transaksi) {
        daftar.add(transaksi)
        jumlahTransaksi += 1
    }

    fun total(): Long = daftar.sumOf { it.nominal }
}

fun main() {
    val t1 = Transaksi(id = 1L, nominal = 50_000L, keterangan = "penjualan buku")
    val t2 = Transaksi(id = 2L, nominal = 75_000L, keterangan = "penjualan pulpen")
    BukuBesar.catat(t1)
    BukuBesar.catat(t2)

    println("$NAMA_APLIKASI v$VERSI")
    println("Jumlah transaksi: $jumlahTransaksi")
    println("Total nominal: ${BukuBesar.total()}")
    println("Pajak atas total: ${hitungPajak(BukuBesar.total(), 0.11)}")
    println("Absolut selisih: ${abs(t1.nominal - t2.nominal)}")
}

Output yang Dihasilkan:

text
Kasir Sederhana v1.0.0
Jumlah transaksi: 2
Total nominal: 125000
Pajak atas total: 13750
Absolut selisih: 25000

Mari kita bedah baris-baris di atas:

  1. Baris 3 (package com.example.berkas): deklarasi package. Semua deklarasi top-level berikutnya akan berada di ruang nama ini.
  2. Baris 8 (fun hitungPajak(...)): function top-level. Pada JVM, function ini akan dikompilasi menjadi static method pada class FileLevelDeclarationsKt (nama class otomatis dari nama file).
  3. Baris 14 (val NAMA_APLIKASI): property read-only top-level. Pada JVM menjadi static getter pada class FileLevelDeclarationsKt.
  4. Baris 17 (const val VERSI): konstanta compile-time. Karena const, nilainya di-inline pada setiap titik pemakaian; tidak ada getter runtime.
  5. Baris 20 (var jumlahTransaksi): property mutable top-level. Mutable global state harus dipakai dengan hati-hati karena dapat membingungkan pada kode multi-thread.
  6. Baris 23 (data class Transaksi): class top-level. Menghasilkan equals, hashCode, toString, dan copy otomatis.
  7. Baris 26-34 (object BukuBesar): singleton top-level. Kompilator memastikan hanya ada satu instance.
  8. Baris 36-46 (fun main): titik masuk program. Memanggil semua deklarasi di atas.

Konvensi Nama File #

Nama file .kt bebas — tidak harus sama dengan nama class. Namun konvensi yang dipakai ekosistem Kotlin adalah:

  • Jika file berisi satu class utama, nama file mengikuti nama class (misalnya Transaksi.kt berisi class Transaksi).
  • Jika file berisi kumpulan function utilitas, gunakan nama deskriptif dalam PascalCase (misalnya StringUtils.kt atau NumberUtils.kt).
  • File berisi extension function biasanya dinamai sesuai tipe yang diperluas, misalnya StringExtensions.kt.

Mengapa Top-Level Berguna #

Deklarasi top-level membuat kode lebih ringkas karena kita tidak perlu membungkus utility function dalam class Util atau Helper seperti di Java. Hal ini juga membantu membaca: function hitungPajak cukup ditulis satu kali, tidak perlu berdebat apakah ditaruh di class PajakUtil atau class TaxHelper.

Referensi Lanjutan #

  • Packages — bagian top-level declaration pada file Kotlin di panduan resmi

Selanjutnya #

Satu file saja kadang tidak cukup untuk proyek nyata. Chapter Multi-File Projects akan membahas bagaimana beberapa file .kt berbagi package dan saling memanggil.