Pada chapter sebelumnya kita berkenalan dengan readln() dan readlnOrNull() sebagai pengganti readLine(). Sekarang kita akan membongkar perilaku keduanya lebih dalam, terutama saat dihadapkan dengan kondisi end-of-file (EOF) dan saat dipakai bersama function parsing seperti toInt(), toDouble(), dan toBoolean(). Pemahaman tentang kapan exception dilempar dan bagaimana rantai pemanggilan method (chaining) bekerja akan membantu kita menulis program CLI yang lebih tangguh.

Perilaku readln() saat EOF #

Function readln() didesain untuk happy path — yaitu ketika stdin masih memiliki baris untuk dibaca. Signature-nya sederhana:

kotlin
public inline fun readln(): String

Karena tipe kembalian String non-null, kompilator menjamin kita mendapat string tanpa perlu pengecekan null. Konsekuensinya, jika readln() dipanggil ketika stdin sudah EOF, runtime akan melempar RuntimeException dengan pesan mirip berikut:

text
Exception in thread "main" java.io.EOFException: Input is empty

Inilah sebabnya readln() paling cocok dipakai ketika program berjalan di terminal interaktif di mana pengguna selalu mengetik baris input. Untuk program yang membaca file atau pipe, gunakan readlnOrNull() agar kondisi EOF dapat ditangani secara eksplisit.

readlnOrNull() dan Null Safety #

Function readlnOrNull() mengembalikan String? — null ketika stdin mencapai EOF. Penggunaannya mengikuti pola null-safety standar Kotlin:

kotlin Contoh: pola readlnOrNull()
val baris = readlnOrNull()
if (baris != null) {
    println("Anda mengetik: $baris")
} else {
    println("Tidak ada input (EOF)")
}

// atau dengan elvis operator
val teks = readlnOrNull() ?: ""
println("Teks aman: $teks")

Pilihan antara readln() dan readlnOrNull() bukan soal preferensi gaya, melainkan soal kontrak: kita ingin program berhenti dengan exception saat EOF, atau kita ingin menanganinya secara terprogram.

Parsing dengan Chained Method #

Kombinasi readln() dengan method parsing adalah pola yang sering muncul di program CLI. Karena readln() mengembalikan String, kita dapat langsung memanggil method parsing pada hasilnya:

kotlin
25
1.75
true
3
85"}
fun main() {
    println("Nama:")
    val nama = readln()
    println("Halo, $nama")

    println("Umur:")
    val umurText = readln()
    val umur = umurText.toInt()
    println("Tahun depan: ${umur + 1}")

    println("Tinggi (meter):")
    val tinggi = readln().toDouble()
    println("Tinggi dalam cm: ${tinggi * 100}")

    println("Aktif (true/false):")
    val aktif = readln().toBoolean()
    println("Status aktif: $aktif")

    println("Jumlah barang:")
    val jumlah = readln().trim().toInt()
    val hargaSatuan = 15000
    val total = jumlah * hargaSatuan
    println("Total: Rp$total")

    println("Skor (0-100):")
    val skor = readln().toInt()
    val kategori = when {
        skor >= 90 -> "A"
        skor >= 80 -> "B"
        skor >= 70 -> "C"
        else -> "D"
    }
    println("Kategori: $kategori")
}

Output yang Dihasilkan:

text
Nama:
Halo, Budi
Umur:
Tahun depan: 26
Tinggi (meter):
Tinggi dalam cm: 175.0
Aktif (true/false):
Status aktif: true
Jumlah barang:
Total: Rp45000
Skor (0-100):
Kategori: B

Mari kita telaah baris-baris kode di atas:

  1. Baris 2–4 (val nama = readln()): function readln() membaca satu baris dan mengembalikan String non-null. Karena prompt sudah mencetak newline sendiri lewat println, baris input pengguna muncul tepat di bawah prompt.
  2. Baris 6–8 (val umurText = readln() lalu umurText.toInt()): pemisahan menjadi dua langkah sengaja dilakukan agar kita melihat rantai pemanggilan secara eksplisit. Method toInt() dari String mengembalikan Int jika teks berisi bilangan bulat valid.
  3. Baris 10–11 (readln().toDouble()): ini adalah bentuk chained call — hasil readln() langsung kita panggil method toDouble(). Karena readln() mengembalikan String non-null, kita dapat memanggil method String secara langsung tanpa operator ?..
  4. Baris 14 (readln().toBoolean()): method toBoolean() di Kotlin mengembalikan true jika teks (case-insensitive) sama dengan "true", sebaliknya false. Tidak seperti Boolean.parseString di Java yang melempar exception, versi Kotlin tidak pernah melempar — string “yes” atau “1” akan menjadi false.
  5. Baris 18 (readln().trim().toInt()): kita mengaitkan tiga method: readln() → trim() → toInt(). Method trim() menghapus spasi di awal dan akhir, sehingga input " 3 " tetap bisa diparsing menjadi 3 tanpa galat.
  6. Baris 24–32 (when { skor >= 90 -> "A" ... }): skor yang sudah diparsing dipakai dalam expression when untuk menentukan kategori. Karena when di Kotlin adalah expression, kita dapat menugaskan hasilnya langsung ke variabel kategori.

Method Parsing yang Umum #

Standard library Kotlin menyediakan dua keluarga method parsing pada String:

MethodTipe kembalianPerilaku saat input invalid
toInt()IntMelempar NumberFormatException
toIntOrNull()Int?Mengembalikan null
toDouble()DoubleMelempar NumberFormatException
toDoubleOrNull()Double?Mengembalikan null
toBoolean()BooleanSelalu berhasil (default false)
toBooleanStrict()BooleanMelempar jika bukan “true”/“false”
toLong(), toFloat(), toShort()tipe masing-masingMelempar saat invalid

Chained Parsing yang Aman #

Saat kita merantai readln().toInt(), dua sumber galat berbeda muncul: readln() dapat melempar saat EOF, dan toInt() dapat melempar saat teks bukan angka valid. Untuk menangani keduanya secara defensif, gunakan kombinasi readlnOrNull() dan toIntOrNull():

kotlin Contoh: parsing aman dengan null
val umur: Int = readlnOrNull()?.toIntOrNull() ?: 0
println("Umur dibaca: $umur")

Rantai di atas tidak akan pernah melempar exception apa pun. Jika readlnOrNull() mengembalikan null, safe call ?. menyebarkan null, lalu elvis ?: memberikan nilai default 0.

readln() di Versi Kotlin Lama #

Sebelum Kotlin 1.6, readln() belum ada di standard library. Pengembang terpaksa memakai readLine()!! yang berisiko melempar NullPointerException (bukan RuntimeException) saat EOF. Sejak 1.6, readln() hadir sebagai pengganti yang lebih jelas peringatannya. Jika menemukan kode lama dengan pola readLine() !!, pertimbangkan untuk migrasi ke readln() atau readlnOrNull().

Referensi Lanjutan #

Dengan pemahaman tentang readln() dan rantai parsing, kita siap beranjak ke topik berikutnya: membaca argumen baris perintah (args) yang diteruskan ke main() saat program dijalankan dari terminal.