Berkutat dengan beberapa tipe data berbeda adalah hal biasa dalam program. Di beberapa bahasa, konversi antar tipe numerik terjadi otomatis (implicit), yang sering menyembunyikan kehilangan presisi atau overflow. Kotlin memilih jalur berbeda: tidak ada konversi numerik implisit — semua konversi wajib eksplisit melalui method seperti .toInt(), .toLong(), atau .toDouble(). Pada chapter ini kita akan membedah konversi tipe, kapan terjadi truncation, kapan terjadi wrap-around, serta konversi dari/ke String dan Char.

Tidak ada konversi implisit #

Berbeda dari Java atau C yang memperbolehkan long l = someInt;, Kotlin menolak kode seperti itu:

kotlin Konversi implisit tidak diizinkan
val i: Int = 5
// val l: Long = i           // galat: type mismatch
val l: Long = i.toLong()     // sah: konversi eksplisit

Aturan ini sengaja diadopsi untuk mencegah kesalahan halus seperti kehilangan presisi saat konversi Long → Int yang tidak disadari. Dengan memaksa eksplisit, pembaca kode menyadari adanya konversi.

Method konversi numerik #

Setiap tipe numerik memiliki method konversi ke semua tipe numerik lain:

DariMethod tersedia
Byte.toShort(), .toInt(), .toLong(), .toFloat(), .toDouble(), .toChar()
Short.toByte(), .toInt(), .toLong(), .toFloat(), .toDouble(), .toChar()
Int.toByte(), .toShort(), .toLong(), .toFloat(), .toDouble(), .toChar()
Long.toByte(), .toShort(), .toInt(), .toFloat(), .toDouble(), .toChar()
Float.toByte(), .toShort(), .toInt(), .toLong(), .toDouble(), .toChar()
Double.toByte(), .toShort(), .toInt(), .toLong(), .toFloat(), .toChar()

Demonstrasi konversi #

Berikut program lengkap yang memperlihatkan berbagai konversi:

kotlin
fun main() {
    val umurInt: Int = 25
    val umurLong: Long = umurInt.toLong()
    val umurDouble: Double = umurInt.toDouble()
    val umurFloat: Float = umurInt.toFloat()
    val umurByte: Byte = umurInt.toByte()
    val umurString: String = umurInt.toString()

    println("umurInt    = $umurInt (${umurInt.javaClass.simpleName})")
    println("umurLong   = $umurLong (${umurLong.javaClass.simpleName})")
    println("umurDouble = $umurDouble (${umurDouble.javaClass.simpleName})")
    println("umurFloat  = $umurFloat (${umurFloat.javaClass.simpleName})")
    println("umurByte   = $umurByte (${umurByte.javaClass.simpleName})")
    println("umurString = $umurString (${umurString.javaClass.simpleName})")

    println()
    val beratString = "65.5"
    val beratDouble = beratString.toDouble()
    val beratFloat = beratString.toFloat()
    val beratInt = beratDouble.toInt()
    println("beratString = $beratString")
    println("beratDouble = $beratDouble")
    println("beratFloat  = $beratFloat")
    println("beratInt    = $beratInt (truncated)")

    println()
    val maxInt = Int.MAX_VALUE
    val maxLongFromInt = maxInt.toLong()
    val overflowInt = (maxLongFromInt + 1).toInt()
    println("Int.MAX_VALUE            = $maxInt")
    println("maxInt.toLong()         = $maxLongFromInt")
    println("(maxInt+1).toInt()      = $overflowInt (wrap-around)")

    println()
    val nilaiDouble = 3.99
    val dibulatkan = nilaiDouble.toInt()
    val dibulatkanRound = Math.round(nilaiDouble).toInt()
    println("nilaiDouble = $nilaiDouble")
    println("toInt()      = $dibulatkan (truncation ke nol)")
    println("Math.round() = $dibulatkanRound")

    println()
    val huruf = '7'
    val kode = huruf.code
    val angkaDariHuruf = huruf.digitToInt()
    println("huruf        = $huruf")
    println("huruf.code   = $kode")
    println("huruf.digitToInt() = $angkaDariHuruf")
}

Output yang Dihasilkan:

text
umurInt    = 25 (int)
umurLong   = 25 (long)
umurDouble = 25.0 (double)
umurFloat  = 25.0 (float)
umurByte   = 25 (byte)
umurString = 25 (String)

beratString = 65.5
beratDouble = 65.5
beratFloat  = 65.5
beratInt    = 65 (truncated)

Int.MAX_VALUE            = 2147483647
maxInt.toLong()         = 2147483647
(maxInt+1).toInt()      = -2147483648 (wrap-around)

nilaiDouble = 3.99
toInt()      = 3 (truncation ke nol)
Math.round() = 4

huruf        = 7
huruf.code   = 55
huruf.digitToInt() = 7

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

  1. Baris 2-8 — konversi Int ke semua tipe numerik lain. toLong() memperluas nilai tanpa kehilangan; toFloat()/toDouble() mempertahankan nilai; toByte() memotong bila nilai di luar range Byte.
  2. Baris 9 (umurString = umurInt.toString()) — konversi numerik ke String via toString(). Berguna untuk penyusunan pesan atau penyimpanan ke file teks.
  3. Baris 13-17 (beratString.toDouble(), dst.) — konversi String ke numerik. "65.5".toDouble() menghasilkan 65.5. Bila string tidak valid, akan memunculkan NumberFormatException.
  4. Baris 18 (beratInt = beratDouble.toInt()) — konversi Double → Int bersifat truncation (pemotongan ke nol). 65.5 menjadi 65; -65.5 menjadi -65.
  5. Baris 23-25 ((maxLongFromInt + 1).toInt()) — maxInt.toLong() + 1 menghasilkan 2.147.483.648 (di luar Int.MAX_VALUE). .toInt() memotong bit ke-32 dan menyebabkan wrap-around ke -2.147.483.648. Tidak ada exception yang dilempar.
  6. Baris 30-31 (toInt() vs Math.round()) — toInt() memotong desimal; Math.round() membulatkan ke bilangan bulat terdekat (0.5 ke atas).
  7. Baris 35-37 (huruf.code, huruf.digitToInt()) — .code mengembalikan kode Unicode ('7'.code = 55); .digitToInt() mengembalikan nilai numerik digit ('7'.digitToInt() = 7). Method kedua hanya valid untuk karakter '0'..'9'.

Konversi String ke numerik #

Beberapa method untuk parse String menjadi numerik:

MethodTipe hasilContohException bila invalid
.toInt()Int"42".toInt()NumberFormatException
.toLong()Long"42L".toLong() gagalNumberFormatException
.toDouble()Double"3.14".toDouble()NumberFormatException
.toFloat()Float"3.14f".toFloat() gagalNumberFormatException
.toIntOrNull()Int?"abc".toIntOrNull() → null(tidak ada exception)
.toDoubleOrNull()Double?"x".toDoubleOrNull() → null(tidak ada exception)

Konversi Char ↔ Int #

Char dan Int dipisahkan secara tipe, tetapi konversi dua arah tersedia:

kotlin Konversi Char-Int
val huruf: Char = 'A'
val kode: Int = huruf.code        // 65
val kembali: Char = kode.toChar() // 'A'

val digit: Char = '5'
val nilai: Int = digit.digitToInt()  // 5

.digitToInt() hanya bekerja untuk '0'..'9'. Untuk karakter di luar rentang ini, gunakan .code untuk mendapatkan nilai Unicode.

Truncation vs rounding #

OperasiHasil untuk 3.99Hasil untuk -3.99
.toInt()3-3 (truncation menuju nol)
Math.round().toInt()4-3 (pembulatan ke terdekat)
Math.floor().toInt()3-4 (pembulatan ke bawah)
Math.ceil().toInt()4-3 (pembulatan ke atas)

Referensi Lanjutan #

  • Type checks and casts — dokumentasi resmi type checks dan casts Kotlin termasuk as, as?, dan is
  • Basic types — rujukan tipe dasar Kotlin untuk memahami konversi eksplisit antar tipe angka

Konversi eksplisit membuat kode lebih aman karena setiap langkah konversi terlihat. Berikutnya, kita akan melihat bagaimana menyederhanakan tipe kompleks dengan type alias — pada chapter Type Aliases.