Sebagian nilai dalam program selayaknya tidak pernah berubah: tarif pajak 11%, batas grade A di angka 90, jumlah maksimal kursi satu gerbong. Kalau nilai seperti itu ditulis ulang di sepuluh tempat berbeda, satu saja yang lupa diperbarui — dan muncullah bug yang sulit dilacak. Java mengatasi persoalan tersebut dengan modifier final: variabel yang hanya boleh diisi satu kali, lalu terkunci selamanya. Pada Chapter ini kita pelajari final pada variabel lokal, konstanta static final level class, serta satu kejutan: final pada variabel reference ternyata tidak mengunci isi objeknya.
Variabel final #
Modifier final pada deklarasi variabel menjadikan variabel tersebut blank hingga diisi sekali. Setelah pengisian pertama, setiap assignment berikutnya ditolak compiler. Dua bentuk pemakaiannya:
- Langsung berisi:
final int harga = 250000;— nilai dikunci pada baris yang sama. - Blank final:
final String grade;dideklarasikan kosong, lalu diisi tepat satu kali di salah satu cabang percabangan. Compiler kembali memakai analisis definite assignment: pengisian boleh ditunda, asalkan setiap jalur eksekusi mengisi variabel tersebut tepat sekali.
Perilaku ini cocok dengan namanya: nilai final adalah nilai akhir. Kebalikan dari variabel biasa yang isinya bebas berganti, variabel final berfungsi sebagai nilai bernama yang terjamin konsisten dari titik inisialisasi hingga akhir scope-nya.
Konstanta Class dengan static final #
Gabungan static final menghasilkan konstanta sejati di level class: satu salinan nilai yang dimiliki class (bukan per-instance, karena static) dan tidak bisa diubah (karena final). Seluruh instance class berbagi nilai yang sama, dan nilai tersebut dapat dipakai tanpa membuat objek terlebih dulu.
Konvensi penamaan konstanta Java adalah kapital semua dengan pemisah garis bawah (UPPER_SNAKE_CASE): TARIF_PPN_PERSEN, BATAS_GRADE_A, MAX_VALUE. Konvensi kapital ini sengaja dibuat kontras dengan camelCase variabel biasa agar pembaca kode langsung mengenali “nilai ini konstan” tanpa perlu memeriksa deklarasinya.
Konstanta dalam Praktik #
Program berikut menghitung total belanja dengan tarif PPN yang terkunci, menentukan grade lewat blank final, lalu menguji perilaku final pada array:
import java.util.Arrays;
public class KonstantaFinal {
static final int TARIF_PPN_PERSEN = 11; // konstanta class, kapital + garis bawah
static final int BATAS_GRADE_A = 90;
public static void main(String[] args) {
final int harga = 250000; // konstanta lokal
long ppn = harga * TARIF_PPN_PERSEN / 100;
long total = harga + ppn;
System.out.println("harga = " + harga);
System.out.println("ppn = " + ppn);
System.out.println("total = " + total);
final String grade; // blank final: belum berisi
int skor = 92;
if (skor >= BATAS_GRADE_A) {
grade = "A"; // pengisian satu-satunya
} else {
grade = "B";
}
System.out.println("grade = " + grade);
final int[] nilai = {80, 90, 70}; // rujukan array terkunci...
nilai[0] = 95; // ...tetapi isinya masih bisa diubah
System.out.println("nilai = " + Arrays.toString(nilai));
}
}Output yang Dihasilkan:
harga = 250000
ppn = 27500
total = 277500
grade = A
nilai = [95, 90, 70]Mari kita bedah baris-baris kuncinya:
- Baris 4-5 (
static final int TARIF_PPN_PERSEN = 11;): konstanta class. Nilai11hidup satu kali untuk seluruh program; mengubah tarif pajak cukup di satu baris ini dan seluruh perhitungan ikut berubah. - Baris 8 (
final int harga = 250000;): konstanta lokal — angka250000kini punya nama yang bermakna, bukan lagi magic number yang melayang tanpa penjelasan. - Baris 16-22 (
final String grade;): blank final. Compiler memeriksa kedua cabangif/elsedan memastikangradeterisi tepat satu kali di jalur manapun sebelum baris 23 membacanya. - Baris 25-26 (
final int[] nilai = ...lalunilai[0] = 95;):finalmengunci rujukan ke array, bukan isi array — baris 26 tetap sah dan mengubah elemen pertama menjadi95.
Mengubah final Ditolak Compiler #
Apa yang terjadi bila konstanta dipaksa diubah? Berkas berikut mencoba assignment kedua terhadap variabel final:
public class FinalDiubah {
public static void main(String[] args) {
final int batas = 10;
batas = 20;
System.out.println(batas);
}
}Compiler javac menolak sebelum program sempat berjalan: error: cannot assign a value to final variable batas. Perhatikan bahwa perlindungan ini terjadi di waktu kompilasi, bukan runtime — tidak ada pengecekan tambahan saat program berjalan sehingga final tidak menambah biaya eksekusi sama sekali.
Nilai yang terkunci dengan final dan konstanta static final melengkapi dasar variabel kita. Berikutnya kita masuk wilayah yang lebih teknis: bagaimana Java memindahkan nilai antar tipe yang berbeda. Konversi paling aman — dari tipe kecil ke tipe besar — terjadi otomatis tanpa perintah tambahan, dan Chapter Type Conversion membahas aturan lengkapnya.
Referensi #
- JLS SE25 §4.12.4: final Variables
- JLS SE25 §13.1: Compile-Time Constants
- Oracle: Variables in Java
- Java API: Math — konstanta E dan PI
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
FinalDiubah.java
Unduh berkaspublic class FinalDiubah {
public static void main(String[] args) {
final int batas = 10;
batas = 20;
System.out.println(batas);
}
}
KonstantaFinal.java
Unduh berkasimport java.util.Arrays;
public class KonstantaFinal {
static final int TARIF_PPN_PERSEN = 11; // konstanta class, kapital + garis bawah
static final int BATAS_GRADE_A = 90;
public static void main(String[] args) {
final int harga = 250000; // konstanta lokal
long ppn = harga * TARIF_PPN_PERSEN / 100;
long total = harga + ppn;
System.out.println("harga = " + harga);
System.out.println("ppn = " + ppn);
System.out.println("total = " + total);
final String grade; // blank final: belum berisi
int skor = 92;
if (skor >= BATAS_GRADE_A) {
grade = "A"; // pengisian satu-satunya
} else {
grade = "B";
}
System.out.println("grade = " + grade);
final int[] nilai = {80, 90, 70}; // rujukan array terkunci...
nilai[0] = 95; // ...tetapi isinya masih bisa diubah
System.out.println("nilai = " + Arrays.toString(nilai));
}
}