Beberapa nilai tidak pernah berubah selama program berjalan: konstanta matematika seperti PI, batas maksimum pengguna, atau nama aplikasi. Untuk nilai-nilai ini, Kotlin menyediakan deklarasi const val yang mengunci nilai pada saat kompilasi dan menyematkannya langsung ke bytecode. Berbeda dari val biasa yang dievaluasi saat runtime, const val tidak memiliki overhead inisialisasi. Pada chapter ini kita akan membedah deklarasi const val, syarat tipe yang diperbolehkan, serta perbedaan dengan val runtime.

Apa itu const val #

Modifier const dipakai bersama val untuk mendeklarasikan konstanta compile-time. Nilai konstanta harus dapat dievaluasi sepenuhnya saat kompilasi — tidak boleh bergantung pada hasil function call, property non-const, atau data runtime.

kotlin Deklarasi const val
const val PI: Double = 3.141592653589793
const val NAMA_APLIKASI: String = "BelajarKotlin"
const val VERSI: Int = 1
const val MAX_PENGGUNA: Int = 100

Setelah dikompilasi, nilai konstanta disisipkan langsung ke bytecode. Saat dipakai, tidak ada lookup property runtime — performa setara dengan literal.

Syarat const val #

Tidak semua val dapat menjadi const val. Syarat berikut wajib dipenuhi:

SyaratKeterangan
Tipe wajib String atau primitiveString, Int, Long, Float, Double, Byte, Short, Boolean, Char
Nilai harus literal atau ekspresi konstantaTidak boleh hasil function call atau property runtime
Lokasi: top-level atau object/companion objectTidak boleh di local variable atau instance property
Tidak boleh varconst hanya untuk val
kotlin Syarat const val
// Sah
const val PI: Double = 3.14
const val NAMA: String = "Kotlin"
const val MAX: Int = 100
const val HEX: Int = 0xFF
const val BITS: Int = 8 * 4           // ekspresi konstanta
const val NAMA_LEN: Int = NAMA.length // ekspresi konstanta dari konstanta lain

// Tidak sah
// const val SEKARANG: Long = System.currentTimeMillis()  // bukan konstanta
// const val DAFTAR: List<Int> = listOf(1, 2, 3)            // List bukan primitive
// fun foo() {
//     const val X: Int = 5                                    // const tidak boleh di local
// }

Lokasi const val #

const val hanya boleh dideklarasikan di:

  1. Top-level — di luar class/function, dalam file .kt.
  2. object — singleton Kotlin.
  3. companion object di dalam class.

Tidak boleh di local variable atau instance property non-object.

kotlin Lokasi const val
// Top-level
const val APP_NAME: String = "BelajarKotlin"

object Konfigurasi {
    const val HOST: String = "localhost"
    const val PORT: Int = 8080
}

class Lingkaran(val radius: Double) {
    companion object {
        const val PI: Double = 3.141592653589793
    }
    fun luas(): Double = PI * radius * radius   // akses: Lingkaran.PI atau PI di dalam
}

Demonstrasi const val #

Berikut program lengkap yang membandingkan const val dengan val biasa:

kotlin
const val PI: Double = 3.141592653589793
const val NAMA_APLIKASI: String = "BelajarKotlin"
const val VERSI: Int = 1
const val MAX_PENGGUNA: Int = 100

object Konfigurasi {
    const val HOST: String = "localhost"
    const val PORT: Int = 8080
    const val TIMEOUT_MS: Int = 5000
}

val waktuMulai: Long = 1_700_000_000_000_000_000L

fun main() {
    println("=== Konstanta top-level (const val) ===")
    println("PI           = $PI")
    println("NAMA_APLIKASI= $NAMA_APLIKASI")
    println("VERSI        = $VERSI")
    println("MAX_PENGGUNA = $MAX_PENGGUNA")

    println()
    println("=== Konstanta di object (const val) ===")
    println("HOST         = ${Konfigurasi.HOST}")
    println("PORT         = ${Konfigurasi.PORT}")
    println("TIMEOUT_MS   = ${Konfigurasi.TIMEOUT_MS}")

    println()
    println("=== Property val biasa (runtime) ===")
    val waktuAksesPertama: Long = 1_700_000_000_000_001_234L
    println("waktuMulai (val)        = $waktuMulai")
    println("waktuAksesPertama (val) = $waktuAksesPertama")
    println("Selisih = ${waktuAksesPertama - waktuMulai} ns")

    println()
    val lingkaran = Lingkaran(5.0)
    println("Lingkaran radius = ${lingkaran.radius}")
    println("Luas lingkaran   = ${lingkaran.luas()}")
    println("Keliling         = ${lingkaran.keliling()}")

    println()
    println("=== Demonstriasi inline const ===")
    println("Maks pengguna x 2 = ${MAX_PENGGUNA * 2}")
    println("URL endpoint       = http://${Konfigurasi.HOST}:${Konfigurasi.PORT}/api")
}

class Lingkaran(val radius: Double) {
    fun luas(): Double = PI * radius * radius
    fun keliling(): Double = 2 * PI * radius
}

Output yang Dihasilkan:

text
=== Konstanta top-level (const val) ===
PI           = 3.141592653589793
NAMA_APLIKASI= BelajarKotlin
VERSI        = 1
MAX_PENGGUNA = 100

=== Konstanta di object (const val) ===
HOST         = localhost
PORT         = 8080
TIMEOUT_MS   = 5000

=== Property val biasa (runtime) ===
waktuMulai (val)        = 1700000000000000000
waktuAksesPertama (val) = 1700000000000001234
Selisih = 1234 ns

Lingkaran radius = 5.0
Luas lingkaran   = 78.53981633974483
Keliling         = 31.41592653589793

=== Demonstriasi inline const ===
Maks pengguna x 2 = 200
URL endpoint       = http://localhost:8080/api

Mari kita amati baris-baris penting pada kode di atas:

  1. Baris 1-4 — const val di top-level. Nilai-nilai ini disematkan ke bytecode sebagai konstanta — tidak ada inisialisasi runtime.
  2. Baris 6-10 (object Konfigurasi) — const val di dalam object singleton. Akses: Konfigurasi.HOST, Konfigurasi.PORT. Sama efisiennya dengan top-level.
  3. Baris 12 (val waktuMulai: Long = ...) — val biasa (tanpa const) di top-level. Nilai tetap disimpan sebagai property static JVM, tetapi inisialisasi terjadi saat class dimuat — tidak seefisien const val.
  4. Baris 14 (fun main()) — penggunaan PI, NAMA_APLIKASI, dll. langsung. Karena const, kompilator menyisipkan nilai literal ke bytecode.
  5. Baris 31-33 (lingkaran.luas(), lingkaran.keliling()) — class Lingkaran memakai PI dari top-level konstanta. Perhitungan menjadi konstan jika input radius juga konstan.
  6. Baris 38 (MAX_PENGGUNA * 2) — ekspresi yang melibatkan konstanta compile-time. Kompilator dapat mengevaluasi MAX_PENGGUNA * 2 saat kompilasi menjadi 200, menyematkan hasilnya sebagai konstanta baru di bytecode.
  7. Baris 39 (http://${Konfigurasi.HOST}:${Konfigurasi.PORT}/api) — string template dengan konstanta. Karena nilai sudah disematkan saat kompilasi, runtime hanya perlu merangkai string — efisien.

const val vs val biasa #

Perbedaan utama dirangkum pada tabel berikut:

Aspekconst valval biasa
Waktu evaluasiCompile-timeRuntime (saat class/instance dimuat)
Tipe yang diizinkanString atau primitive sajaSemua tipe
LokasiTop-level, object, companion objectMana saja
Overhead inisialisasiTidak ada (inline ke bytecode)Ada (akses field statis)
Bisa untuk varTidakTidak relevan
Bisa untuk nilai hasil functionTidakYa

Kapan memilih const val #

SkenarioPilihan
Konstanta matematika (PI, E)const val
Batas aplikasi (MAX_PENGGUNA, TIMEOUT_DETIK)const val
Versi aplikasi, nama aplikasiconst val
Nilai yang bergantung pada config runtimeval biasa
Nilai hasil function call (System.currentTimeMillis())val biasa
Koleksi (listOf(...))val biasa

Referensi Lanjutan #

  • Properties — dokumentasi properti Kotlin yang merincikan perbedaan const val (compile-time) dan val (runtime)
  • Coding conventions — panduan konvensi penamaan Kotlin untuk const val dan konstanta tingkat atas

Penggunaan const val yang tepat membuat program lebih efisien dan kode lebih jelas. Berikutnya, kita akan melihat bagaimana variabel hidup dan mati dalam scope blok — pada chapter Scope dan Lifetime.