Salah satu kekuatan utama Kotlin adalah interoperabilitas penuh dengan Java: kode Kotlin dapat memakai library Java tanpa wrapper, tanpa JNI, tanpa boilerplate. Kita dapat membuat instance java.util.ArrayList langsung, memanggil Math.max(...), dan mengakses LocalDate.getDayOfMonth() seolah-olah semua itu kode Kotlin asli. Bab ini membahas tiga aspek inti pemanggilan Java dari Kotlin: konstruksi tanpa new, pemakaian static method, dan transformasi otomatis getter/setter menjadi properti.

Tiga Aturan Utama Interoperabilitas #

Saat memakai kode Java dari Kotlin, tiga aturan berikut berlaku konsisten:

AturanJavaKotlin
Konstruksi objeknew ArrayList<Integer>()ArrayList<Int>() (tanpa new)
Method statisMath.max(a, b)Math.max(a, b) (sama persis)
Getter/setterdate.getDayOfMonth()date.dayOfMonth (properti sintaks)

Tidak ada wrapper, tidak ada adaptasi manual. Yang berubah hanya sintaks pemanggilan: kata kunci new dihapus, dan getter getXxx() menjadi properti .xxx.

Contoh Lengkap: Memakai Koleksi, Static, dan File Java #

Kode berikut memakai beberapa kelas Java sekaligus — ArrayList, HashMap, Properties, LocalDate, File, Math, System, dan Collections:

kotlin
import java.util.ArrayList
import java.util.HashMap
import java.time.LocalDate
import java.io.File

// Demonstrasi pemanggilan kode Java dari Kotlin:
// - Konstruktor Java langsung dipakai tanpa 'new'
// - Static method dipanggil seperti biasa
// - Getter/setter Java otomatis menjadi properti Kotlin

class Konfigurasi {
    // Memakai kelas Java java.util.Properties sebagai field
    private val prop: java.util.Properties = java.util.Properties()

    fun simpan(kunci: String, nilai: String) {
        prop.setProperty(kunci, nilai)   // method Java setProperty
    }

    fun ambil(kunci: String): String? = prop.getProperty(kunci)  // getProperty mengembalikan String?
}

fun main() {
    // 1. Memakai kelas Java koleksi: java.util.ArrayList
    val daftar: ArrayList<Int> = ArrayList<Int>()
    daftar.add(10)
    daftar.add(20)
    daftar.add(30)
    println("=== java.util.ArrayList ===")
    println("daftar        : $daftar")
    println("ukuran        : ${daftar.size}")           // getter -> properti
    println("elemen ke-1   : ${daftar[1]}")            // index access -> get(1)

    // 2. java.util.HashMap dengan operator Kotlin
    val peta: HashMap<String, String> = HashMap()
    peta["nama"] = "Budi"                               // setProperty via Kotlin
    peta["email"] = "[email protected]"
    println()
    println("=== java.util.HashMap ===")
    println("peta          : $peta")
    println("nama          : ${peta["nama"]}")          // peta.get("nama")
    println("tidakAda      : ${peta["tidakAda"]}")     // null (platform type)

    // 3. Static method Java: Math, System, Collections
    println()
    println("=== Static method Java ===")
    println("Math.max(3,7) : ${Math.max(3, 7)}")
    println("Math.abs(-5)  : ${Math.abs(-5)}")
    println("System.lineSeparator().length: ${System.lineSeparator().length}")

    val tidakDiubah = java.util.Collections.unmodifiableList(daftar)
    println("unmodifiable  : $tidakDiubah")

    // 4. Getter/setter Java otomatis menjadi properti Kotlin
    val tanggal = LocalDate.of(2026, 1, 15)
    println()
    println("=== Getter sebagai properti ===")
    println("tanggal       : $tanggal")
    println("tahun         : ${tanggal.year}")          // getYear() -> year
    println("bulan         : ${tanggal.monthValue}")   // getMonthValue() -> monthValue
    println("hari          : ${tanggal.dayOfMonth}")   // getDayOfMonth() -> dayOfMonth

    // 5. Memakai kelas Java I/O: File
    val berkas: File = File("/tmp/belajar_kotlin_calling_java.txt")
    berkas.writeText("Halo dari Kotlin\nBaris kedua\n")
    println()
    println("=== java.io.File ===")
    println("path          : ${berkas.absolutePath}")
    println("ukuran (byte) : ${berkas.length()}")      // length() -> length
    println("ada?          : ${berkas.exists()}")     // exists() -> exists
    println("isi           :")
    berkas.readLines().forEach { println("  | $it") }
    berkas.delete()                                     // hapus file setelah dipakai

    // 6. Memakai Konfigurasi lokal yang membungkus java.util.Properties
    val cfg = Konfigurasi()
    cfg.simpan("versi", "1.0.0")
    cfg.simpan("mode", "produksi")
    println()
    println("=== Wrapper java.util.Properties ===")
    println("versi         : ${cfg.ambil("versi")}")
    println("tidakAda      : ${cfg.ambil("tidakAda")}")
}

Output yang Dihasilkan:

text
=== java.util.ArrayList ===
daftar        : [10, 20, 30]
ukuran        : 3
elemen ke-1   : 20

=== java.util.HashMap ===
peta          : {nama=Budi, [email protected]}
nama          : Budi
tidakAda      : null

=== Static method Java ===
Math.max(3,7) : 7
Math.abs(-5)  : 5
System.lineSeparator().length: 1
unmodifiable  : [10, 20, 30]

=== Getter sebagai properti ===
tanggal       : 2026-01-15
tahun         : 2026
bulan         : 1
hari          : 15

=== java.io.File ===
path          : /tmp/belajar_kotlin_calling_java.txt
ukuran (byte) : 29
ada?          : true
isi           :
  | Halo dari Kotlin
  | Baris kedua

=== Wrapper java.util.Properties ===
versi         : 1.0.0
tidakAda      : null

Mari kita telaah baris-baris kode di atas:

  1. Baris 14 (ArrayList<Int>()): konstruktor Java dipanggil tanpa new. Tipe generik Java Integer secara otomatis dipetakan ke Int Kotlin (autoboxing transparan). daftar.add(10) memanggil ArrayList.add(Integer) secara langsung.
  2. Baris 25 (peta["nama"] = "Budi"): operator Kotlin [] pada java.util.HashMap diterjemahkan ke put("nama","Budi"). Membaca peta["nama"] diterjemahkan ke get("nama"). Hasil get() dari Java adalah tipe platform — Kotlin memperlakukannya sebagai String? (nullable) untuk keamanan.
  3. Baris 33-36 (Math.max, System.lineSeparator()): method statis Java dipanggil persis seperti di Java. Kotlin tidak mengganti sintaks pemanggilan statik. System.lineSeparator() mengembalikan String — perhatikan bahwa di Linux ini hanya satu karakter \n, sehingga .length bernilai 1.
  4. Baris 43 (tanggal.year, tanggal.monthValue): getter Java getYear() dan getMonthValue() otomatis menjadi properti Kotlin year dan monthValue. Kompilator mendeteksi pasangan getXxx/setXxx dan menyajikan ulang sebagai properti. Pemanggilan tanggal.getDayOfMonth() pun juga valid, namun sintaks properti lebih idiomatik.
  5. Baris 50-57 (berkas.writeText(...), berkas.readLines()): java.io.File tidak punya method writeText di sisi Java. Method ini adalah extension function yang ditambahkan Kotlin ke File melalui standard library. Kotlin menambah banyak helper seperti ini tanpa mengubah kelas Java asli.
  6. Baris 62-66 (Konfigurasi lokal): kelas Kotlin sendiri memakai java.util.Properties sebagai field privat. Tipe kembalian prop.getProperty(kunci) dideklarasikan eksplisit sebagai String? agar pemanggil Kotlin tahu bahwa nilai bisa null bila kunci tidak ditemukan.

Operator Kotlin di Atas Koleksi Java #

Kotlin menambah beberapa operator pada koleksi Java yang membuat pemakaian lebih ringkas:

Operator KotlinPemanggilan Java Ekuivalen
daftar[i]daftar.get(i)
daftar[i] = xdaftar.set(i, x) / daftar.add(i, x)
peta[k]peta.get(k)
peta[k] = vpeta.put(k, v)
daftar += xdaftar.add(x) (untuk MutableList)
daftar -= xdaftar.remove(x) (untuk MutableList)

Operator [] dan += membuat kode terlihat idiomatik Kotlin walau di balik layar memakai method Java. Pemakaian ini tidak menambah overhead — kompilator menerjemahkan langsung ke method Java asli.

Referensi Lanjutan #

Selanjutnya #

Arah sebaliknya — memanggil kode Kotlin dari Java — juga penuh sehingga kedua bahasa dapat saling memakai library. Bab Calling Kotlin from Java akan membahas bagaimana top-level function Kotlin dilihat sebagai method statis di Java, serta peran anotasi @JvmStatic dan @JvmOverloads.