Kotlin memiliki tiga tipe khusus yang menempati posisi unik dalam sistem tipenya: Any, Unit, dan Nothing. Any adalah akar hierarki tipe non-nullable; Unit adalah tipe dengan tepat satu nilai, digunakan saat function tidak mengembalikan apa-apa; Nothing adalah tipe yang tidak memiliki nilai sama sekali, merepresentasikan computation yang tidak pernah selesai. Pada chapter ini kita akan membedah ketiganya beserta perannya dalam sistem tipe Kotlin.

Any — akar non-nullable #

Any adalah superclass dari semua tipe non-nullable di Kotlin. Setiap tipe seperti Int, String, Boolean, atau List<T> adalah subtype dari Any. Any setara dengan Object di Java, tetapi Any tidak mengizinkan null — untuk versi nullable, gunakan Any?.

kotlin Any sebagai tipe umum
val a: Any = 42           // Int -> Any
val b: Any = "halo"       // String -> Any
val c: Any = listOf(1, 2) // List<Int> -> Any

Any cocok dipakai ketika kita perlu menampung nilai dengan tipe yang tidak diketahui atau sangat beragam. Namun, di Kotlin idiomatik, kita lebih sering memakai generics atau sealed class untuk type-safety yang lebih baik.

Any memiliki method dasar: toString(), equals(other), hashCode().

Unit — padanan void yang merupakan tipe #

Unit adalah tipe dengan tepat satu nilai, yaitu Unit itu sendiri. Function yang tidak mengembalikan nilai apapun secara implisit mengembalikan Unit. Berbeda dari void di Java (yang bukan tipe), Unit adalah tipe yang sesungguhnya — bisa dipakai sebagai parameter generik, disimpan dalam variabel, atau dikembalikan sebagai nilai.

kotlin Unit sebagai tipe
fun cetak(data: Any): Unit {
    println("Data: $data")
    return Unit           // opsional; implisit jika tidak ditulis
}

val hasil: Unit = cetak("halo")   // hasil = Unit

Karena Unit adalah tipe, kita bisa memakainya sebagai parameter generik:

kotlin Unit sebagai parameter generik
val daftarAksi: List<() -> Unit> = listOf(
    { println("aksi 1") },
    { println("aksi 2") }
)

Tanpa Unit, kita harus memakai tipe Void (reference) di Java, yang memerlukan null sebagai nilai. Unit menghindari overhead boxing ini.

Nothing — tipe yang tidak pernah kembali #

Nothing adalah tipe yang tidak memiliki nilai sama sekali. Nothing dipakai untuk function yang tidak pernah mengembalikan kontrol ke pemanggil — entah karena melempar exception atau karena loop tak berakhir.

kotlin Nothing untuk function yang melempar exception
fun gagal(pesan: String): Nothing {
    throw IllegalStateException(pesan)
}

Karena gagal tidak pernah kembali, kompilator memperbolehkan kita menulis:

kotlin Nothing dalam ekspresi
val nilai: String = try {
    ambilDariDB()
} catch (e: Exception) {
    gagal("database gagal: ${e.message}")
    // kompilator tahu baris ini tidak pernah mencapai sini
}

Nothing adalah subtype dari semua tipe lain, sehingga gagal(...) dapat menggantikan tipe apa pun dalam ekspresi.

kotlin Nothing untuk loop tak berakhir
fun loopSelamanya(): Nothing {
    while (true) {
        // tidak pernah kembali
    }
}

Nothing? — nullable never #

Nothing? adalah tipe yang hanya bisa menampung null. Nothing? menjadi subtype dari semua tipe nullable. Beberapa idiom Kotlin memanfaatkan Nothing?:

  • null literal memiliki tipe Nothing?.
  • Saat kita menulis val x = null, tipe x adalah Nothing?.
  • elvis operator ?: memanfaatkan sifat ini untuk memberikan default ketika operand kiri null.
kotlin Nothing? dalam elvis operator
val nama: String? = ambilNama()
val aman: String = nama ?: "default"
// tipe ?: default bila nama null

Demonstrasi Any, Unit, Nothing #

Berikut program lengkap yang memperlihatkan ketiga tipe khusus:

kotlin
fun cetak(data: Any): Unit {
    println("Data: $data (tipe ${data::class.simpleName})")
    return Unit
}

fun gagal(pesan: String): Nothing {
    throw IllegalStateException(pesan)
}

fun loopSelamanya(): Nothing {
    while (true) {
        // loop tanpa akhir
    }
}

fun main() {
    val angka: Any = 42
    val teks: Any = "Budi"
    val daftar: Any = listOf(1, 2, 3)

    cetak(angka)
    cetak(teks)
    cetak(daftar)

    println()
    println("Tipe Unit:")
    val hasilUnit: Unit = cetak("selesai")
    println("hasilUnit = $hasilUnit")
    println("Unit.toString() = ${Unit.toString()}")

    println()
    println("Any sebagai root non-nullable:")
    println("angka::class = ${angka::class}")
    println("teks::class  = ${teks::class}")

    println()
    val mungkinGagal: String? = try {
        "berhasil"
    } catch (e: Exception) {
        gagal("terjadi galat: ${e.message}")
    }
    println("mungkinGagal = $mungkinGagal")

    println()
    println("Nothing? sebagai nilai default nullable yang tidak mungkin tidak-null:")
    val nilai: String? = null
    val aman = nilai ?: "default"
    println("nilai (null) ?: default = $aman")
}

Output yang Dihasilkan:

text
Data: 42 (tipe Int)
Data: Budi (tipe String)
Data: [1, 2, 3] (tipe ArrayList)

Tipe Unit:
Data: selesai (tipe String)
hasilUnit = kotlin.Unit
Unit.toString() = kotlin.Unit

Any sebagai root non-nullable:
angka::class = class kotlin.Int
teks::class  = class kotlin.String

mungkinGagal = berhasil

Nothing? sebagai nilai default nullable yang tidak mungkin tidak-null:
nilai (null) ?: default = default

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

  1. Baris 1-4 (fun cetak(data: Any): Unit) — function menerima Any (tipe umum) dan mengembalikan Unit. Penulisan : Unit eksplisit opsional — bila tidak ditulis, kompilator menyimpulkan Unit.
  2. Baris 6-8 (fun gagal(pesan): Nothing) — function melempar exception; karena tidak pernah kembali, return type Nothing adalah representasi tepat. Nothing adalah subtype dari semua tipe, sehingga gagal(...) dapat dipakai dalam ekspresi tipe apapun.
  3. Baris 10-14 (fun loopSelamanya(): Nothing) — loop tak berakhir; Nothing menandakan kontrol tidak akan kembali ke pemanggil.
  4. Baris 17-19 (val angka: Any = 42) — Int (non-nullable) di-promosikan ke Any. Hal yang sama untuk String dan List<Int>.
  5. Baris 28 (val hasilUnit: Unit = cetak("selesai")) — function cetak mengembalikan Unit. hasilUnit bernilai kotlin.Unit (instance tunggal).
  6. Baris 36-39 (try { ... } catch { gagal(...) }) — cabang catch memanggil gagal(...) yang return Nothing. Karena Nothing adalah subtype dari String, kompilator mengangkat tipe seluruh ekspresi try ke String (bukan String?), sehingga mungkinGagal tidak perlu ?.
  7. Baris 43-45 (nilai ?: "default") — nilai adalah String? (yang bisa null). ?: memberi default "default" jika nilai null. Tipe aman menjadi String (non-nullable).

Perbandingan tipe #

TipeJumlah nilaiKegunaan utama
Anytak terhingga (semua objek non-null)Tipe umum pengganti Object Java
Any?tak terhingga + nullTipe umum yang mengizinkan null
Unit1 (Unit saja)Function yang “tidak mengembalikan apa-apa”
Nothing0Function yang tidak kembali (throw, infinite loop)
Nothing?1 (null saja)Tipe literal null

Referensi Lanjutan #

  • Basic types — pengantar tipe dasar Kotlin yang memperkenalkan Any, Unit, dan Nothing sebagai pondasi hierarki tipe

Pemahaman tipe khusus ini melengkapi gambaran sistem tipe Kotlin. Berikutnya, kita akan melihat bagaimana mengubah nilai dari satu tipe ke tipe lain melalui konversi eksplisit — pada chapter Type Conversion.