Bilangan bulat adalah tipe data paling sering dipakai dalam program. Kotlin menyediakan empat tipe integer signed: Byte, Short, Int, dan Long, masing-masing dengan lebar bit 8, 16, 32, dan 64. Selain itu, Kotlin juga menyediakan tipe unsigned (UByte, UShort, UInt, ULong) untuk kasus ketika kita tahu nilai tidak pernah negatif. Pada chapter ini kita akan membedah rentang masing-masing tipe, perilaku overflow yang melingkari batas, serta perkenalan singkat tipe unsigned.

Empat tipe integer signed #

Setiap tipe integer signed memiliki rentang simetris di sekitar nol:

TipeLebarRentangMemori
Byte8 bit-128 .. 1271 byte
Short16 bit-32.768 .. 32.7672 byte
Int32 bit-2.147.483.648 .. 2.147.483.6474 byte
Long64 bit-9.223.372.036.854.775.808 .. 9.223.372.036.854.775.8078 byte

Int adalah tipe default untuk bilangan bulat literal. Saat kita menulis 42, kompilator menyimpulkan Int. Untuk Long, gunakan suffix L (misalnya 42L).

Demonstrasi tipe dan rentang #

Berikut program yang memperlihatkan rentang dan contoh penggunaan setiap tipe:

kotlin
fun main() {
    println("Range tipe integer:")
    println("Byte  : ${Byte.MIN_VALUE} .. ${Byte.MAX_VALUE}  (${Byte.SIZE_BITS} bit)")
    println("Short : ${Short.MIN_VALUE} .. ${Short.MAX_VALUE}  (${Short.SIZE_BITS} bit)")
    println("Int   : ${Int.MIN_VALUE} .. ${Int.MAX_VALUE} (${Int.SIZE_BITS} bit)")
    println("Long  : ${Long.MIN_VALUE} .. ${Long.MAX_VALUE} (${Long.SIZE_BITS} bit)")

    println()
    val kapasitasByte: Byte = 100
    val kapasitasShort: Short = 30_000
    val jumlahItem: Int = 2_000_000
    val mikrodetik: Long = 1_500_000_000L

    println("kapasitasByte  = $kapasitasByte")
    println("kapasitasShort = $kapasitasShort")
    println("jumlahItem     = $jumlahItem")
    println("mikrodetik     = $mikrodetik")

    println()
    println("Demonstrasi overflow (wrap-around):")
    val maxInt = Int.MAX_VALUE
    val tambahSatu = maxInt + 1
    println("Int.MAX_VALUE  = $maxInt")
    println("maxInt + 1     = $tambahSatu  <- terbungkus ke minimum")

    val maxByte = Byte.MAX_VALUE
    val toByteOverflow = (maxByte + 1).toByte()
    println("Byte.MAX_VALUE = $maxByte")
    println("(maxByte+1).toByte() = $toByteOverflow")

    println()
    println("Tipe unsigned:")
    val uByte: UByte = 200u
    val uShort: UShort = 60_000u
    val uInt: UInt = 4_000_000_000u
    val uLong: ULong = 18_000_000_000_000_000_000u
    println("uByte  = $uByte  (range ${UByte.MIN_VALUE} .. ${UByte.MAX_VALUE})")
    println("uShort = $uShort  (range ${UShort.MIN_VALUE} .. ${UShort.MAX_VALUE})")
    println("uInt   = $uInt")
    println("uLong  = $uLong")
}

Output yang Dihasilkan:

text
Range tipe integer:
Byte  : -128 .. 127  (8 bit)
Short : -32768 .. 32767  (16 bit)
Int   : -2147483648 .. 2147483647 (32 bit)
Long  : -9223372036854775808 .. 9223372036854775807 (64 bit)

kapasitasByte  = 100
kapasitasShort = 30000
jumlahItem     = 2000000
mikrodetik     = 1500000000

Demonstrasi overflow (wrap-around):
Int.MAX_VALUE  = 2147483647
maxInt + 1     = -2147483648  <- terbungkus ke minimum
Byte.MAX_VALUE = 127
(maxByte+1).toByte() = -128

Tipe unsigned:
uByte  = 200  (range 0 .. 255)
uShort = 60000  (range 0 .. 65535)
uInt   = 4000000000
uLong  = 18000000000000000000

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

  1. Baris 2-5 (Byte.MIN_VALUE dst.) — setiap tipe integer memiliki properti MIN_VALUE dan MAX_VALUE. Property ini berguna untuk validasi sebelum konversi tipe.
  2. Baris 8-11 — deklarasi dengan tipe eksplisit. Byte cocok untuk data biner (0-255 signed menjadi -128..127); Long wajib untuk angka di luar Int.MAX_VALUE.
  3. Baris 17-18 (maxInt + 1) — penambahan Int.MAX_VALUE + 1 menghasilkan Int.MIN_VALUE karena wrap-around. Tidak ada exception yang dilempar; kompilator membiarkan operasi berjalan dan hasilnya melingkar.
  4. Baris 21-22 ((maxByte + 1).toByte()) — maxByte + 1 menghasilkan Int (128). .toByte() memotong ke Byte, yang melingkari ke -128. Ini menunjukkan bahwa operasi aritmatika pada Byte/Short di-promosikan ke Int dahulu.
  5. Baris 27-30 (200u, dst.) — suffix u menandakan literal unsigned. UByte 200 sah karena muat di rentang unsigned 0 .. 255, padahal pada Byte signed nilai 200 tidak valid.

Perilaku overflow #

Kotlin tidak memeriksa overflow integer saat runtime. Operasi yang melampaui batas akan wrap-around:

kotlin Overflow wrap-around
val max = Int.MAX_VALUE      // 2147483647
val overflow = max + 1        // -2147483648 (wrap-around)

val min = Int.MIN_VALUE       // -2147483648
val underflow = min - 1       // 2147483647 (wrap-around)

Untuk mendeteksi overflow secara eksplisit, Kotlin menyediakan method addExact, multiplyExact, subtractExact pada java.lang.Math:

kotlin Deteksi overflow dengan Math
import java.lang.Math.multiplyExact

val aman = multiplyExact(1_000_000, 1_000_000)  // 1_000_000_000
// val bahaya = multiplyExact(Int.MAX_VALUE, 2)  // ArithmeticException

Promosi tipe pada operasi #

Berikut tabel promosi otomatis pada operasi aritmatika:

Operan kiriOperan kananHasil
ByteByteInt
ShortShortInt
IntIntInt
LongLongLong
IntLongLong

Promosi ini adalah warisan JVM untuk efisiensi CPU. Kita tetap dapat menulis kode yang menggunakan Byte/Short, tetapi harus sadar bahwa hasil operasi akan menjadi Int.

Perkenalan tipe unsigned #

Tipe unsigned berguna ketika kita tahu nilai tidak pernah negatif:

TipeLebarRentangContoh penggunaan
UByte8 bit0 .. 255Komponen RGB, byte stream
UShort16 bit0 .. 65.535Port jaringan, code point UTF-16
UInt32 bit0 .. 4.294.967.295ID database di atas 2^31
ULong64 bit0 .. 2^64-1Ukuran file besar, hash

Penggunaan tipe unsigned dibahas tuntas pada chapter Unsigned Integer Types, termasuk kapan memakainya dan kapan menghindarinya.

Referensi Lanjutan #

  • Numbers — dokumentasi tipe angka Kotlin yang merinci ukuran dan rentang Byte, Short, Int, serta Long

Pemilihan tipe integer bergantung pada rentang nilai dan kebutuhan memori. Berikutnya, kita akan melihat tipe floating-point dan jebakan presisi yang menyertainya — materi pada chapter Floating-Point Types.