Kompilasi dan Eksekusi

Menelusuri perjalanan berkas .java menjadi .class lalu dijalankan JVM, dari javac sampai tombol run di IDE.

Daftar isi

Topik ini menelusuri perjalanan sebuah program Java dari berkas teks sampai keluaran muncul di layar. Perjalanannya melewati dua aktor utama, yaitu kompiler javac yang menerjemahkan kode sumber menjadi bytecode, dan mesin virtual Java (Java Virtual Machine, JVM) yang mengeksekusinya. Setelah selesai membaca, dua perintah klasik javac dan java tidak lagi tertukar, dan tombol run di IDE terasa sebagai singkatan dari langkah-langkah yang sudah dipahami.

Dari kode sumber ke bytecode#

Kode yang ditulis pengembang adalah teks yang nyaman dibaca manusia, sedangkan JVM hanya mengerti satu bahasa, yaitu bytecode. Kompilator javac menjembatani keduanya. Kompilator ini membaca berkas .java, memeriksa sintaks dan kecocokan tipe, lalu menghasilkan berkas .class yang berisi bytecode, yakni rangkaian instruksi untuk mesin virtual dan bukan untuk prosesor tertentu.

Alur lengkapnya digambarkan berikut ini.

Halo.javakode sumber JavaHalo.classbytecode Javaprogram berjalandi atas JVMjavacJVMkompilasi dilakukan sekali setiap kali kode berubahJVM mengeksekusi bytecode setiap kali program dijalankan
Alur dari kode sumber sampai program berjalan

Desain dua lapis inilah alasan slogan write once, run anywhere bisa bekerja. Kompilasi menghasilkan bytecode yang sama untuk semua platform, sedangkan setiap sistem operasi punya JVM miliknya yang menerjemahkan bytecode tersebut ke mesin masing-masing. Konsekuensinya, berkas .class hasil kompilasi di Linux dapat dijalankan di Windows tanpa kompilasi ulang, asalkan di sana terpasang JVM.

Dua langkah klasik dengan javac#

Cara tradisional menjalankan Java terdiri atas dua perintah. Perintah pertama mengompilasi, dan perintah kedua menjalankan hasilnya.

bash
# tidak-dijalankan
# langkah 1, mengompilasi Halo.java menjadi Halo.class
javac Halo.java
# langkah 2, menjalankan kelas Halo di atas JVM
java Halo

Perhatikan perbedaan argumennya. Perintah javac menerima nama berkas lengkap dengan ekstensi .java, sedangkan perintah java menerima nama kelas tanpa ekstensi apa pun. Jika kompilasi berhasil, berkas Halo.class muncul di folder yang sama. Bila kompilasi gagal, javac menampilkan daftar error dengan nomor barisnya, dan tidak ada berkas .class yang dihasilkan sampai kesalahan diperbaiki.

Setelah .class ada, perintah java Halo memuat kelas itu, mencari metode main, lalu mengeksekusinya. Berkas .class inilah yang dibagikan ke pengguna aplikasi, karena berkas sumber .java tidak diperlukan lagi pada saat program dijalankan.

Satu langkah dengan mode single-file#

Sejak Java 11, launcher java dapat menjalankan berkas sumber secara langsung dalam satu perintah, tanpa javac dan tanpa berkas .class yang tertinggal. Mode ini disebut mode single-file source, dan perintahnya berbentuk java Nama.java dengan nama berkas sebagai argumennya.

bash
# mode single-file, langsung dari berkas sumber
java Sapa.java
text Keluaran
Kompilasi selesai, saatnya dieksekusi
Bytecode dijalankan oleh JVM
Program berakhir dengan normal

Di balik layar, launcher tetap mengompilasi berkas tersebut, tetapi hasilnya disimpan di memori dan tidak pernah ditulis ke disk. Untuk program kecil dan untuk tahap belajar, mode ini memangkas satu langkah sekaligus menghilangkan risiko menjalankan .class yang lama. Untuk proyek berukuran besar, alat bantu seperti Maven atau Gradle tetap menjadi pilihan karena keduanya mengatur ketergantungan dan kompilasi banyak berkas sekaligus.

Apa yang terjadi di dalam JVM#

JVM bukan penerjemah buta yang membaca bytecode baris demi baris dari awal sampai akhir. Sebelum program berjalan, JVM melakukan beberapa tahap. Kelas yang dibutuhkan dimuat (loading) dari berkas .class, lalu bytecode diverifikasi agar tidak merusak memori, dan setelah itu eksekusi dimulai.

Selama eksekusi, JVM mengamati bagian kode yang paling sering dijalankan dan mengompilasinya menjadi instruksi mesin asli melalui teknik just-in-time (JIT). Hasilnya, program yang berjalan lama semakin cepat karena jalur panasnya sudah berupa kode mesin, bukan bytecode yang ditafsirkan berulang. JVM juga mengelola memori otomatis, termasuk membebaskan objek yang tidak lagi dirujuk melalui proses garbage collection. Bagian-bagian ini memang jauh dari mata, tetapi mengetahui keberadaannya menjelaskan mengapa keluaran program tidak bergantung pada prosesor apa yang dipakai.

Tombol run di IDE#

Tombol run di IntelliJ IDEA, VS Code, atau NetBeans membungkus seluruh alur di atas menjadi satu klik. Di belakangnya, IDE memanggil kompiler untuk semua berkas yang berubah, melaporkan error sebelum program dijalankan, lalu memanggil JVM untuk kelas yang memuat main. Folder hasil kompilasi biasanya bernama out, bin, atau target tergantung alat bantunya.

Keunggulan tambahan IDE terjadi jauh sebelum tombol run ditekan. Editor IDE menandai kesalahan tipe dan sintaks saat kode sedang diketik, melengkapi nama metode secara otomatis, dan menawarkan perbaikan cepat. Dengan begitu banyak error kompilasi terselesaikan sebelum sempat menjadi perintah yang gagal. Terminal tetap bernilai karena perilakunya transparan, sedangkan IDE bernilai karena kecepatan umpan baliknya, dan keduanya memakai mekanisme kompilasi yang sama.

Kesalahan umum#

  • Menjalankan java Sapa.class. JVM mencari kelas bernama Sapa.class dan menampilkan Error: Could not find or load main class Sapa.class. Perbaikannya menulis nama kelas tanpa ekstensi, yaitu java Sapa, atau java Sapa.java untuk mode single-file.
  • Mengedit kode lalu lupa menyimpan berkas sebelum menjalankan. Program tetap berperilaku seperti versi lama karena JVM mengeksekusi versi terakhir yang tersimpan. Kebiasaan menyimpan, atau pengaturan simpan otomatis, menghilangkan kebingungan ini.
  • javac tidak dikenali dengan pesan command not found. Penyebabnya umumnya JDK belum terpasang atau folder biner JDK belum masuk ke PATH. Instalasi JDK dan pemeriksaan javac -version menyelesaikannya.
  • Mengira .class harus dibuat dahulu sebelum mode single-file bisa dipakai. Kedua jalur itu berdiri sendiri, karena java Sapa.java mengompilasi di memori tanpa menyentuh berkas .class mana pun.

Ringkasan#

  • Kompilator javac menerjemahkan berkas .java menjadi berkas .class berisi bytecode, dan JVM mengeksekusi bytecode tersebut di platform mana pun yang punya JVM.
  • Jalur klasik terdiri atas javac Nama.java lalu java Nama, dengan perbedaan penting bahwa java menerima nama kelas tanpa ekstensi.
  • Mode single-file java Nama.java mengompilasi di memori dan langsung menjalankan program, sehingga cocok untuk program kecil dan tahap belajar.
  • JVM memuat dan memverifikasi kelas, mengeksekusi bytecode, mengompilasi jalur panas dengan JIT, dan mengelola memori lewat garbage collection.

Referensi#