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:

text
harga  = 250000
ppn    = 27500
total  = 277500
grade  = A
nilai  = [95, 90, 70]

Mari kita bedah baris-baris kuncinya:

  1. Baris 4-5 (static final int TARIF_PPN_PERSEN = 11;): konstanta class. Nilai 11 hidup satu kali untuk seluruh program; mengubah tarif pajak cukup di satu baris ini dan seluruh perhitungan ikut berubah.
  2. Baris 8 (final int harga = 250000;): konstanta lokal — angka 250000 kini punya nama yang bermakna, bukan lagi magic number yang melayang tanpa penjelasan.
  3. Baris 16-22 (final String grade;): blank final. Compiler memeriksa kedua cabang if/else dan memastikan grade terisi tepat satu kali di jalur manapun sebelum baris 23 membacanya.
  4. Baris 25-26 (final int[] nilai = ... lalu nilai[0] = 95;): final mengunci rujukan ke array, bukan isi array — baris 26 tetap sah dan mengubah elemen pertama menjadi 95.

Mengubah final Ditolak Compiler #

Apa yang terjadi bila konstanta dipaksa diubah? Berkas berikut mencoba assignment kedua terhadap variabel final:

java FinalDiubah.java
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 #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

FinalDiubah.java

Unduh berkas
java
public class FinalDiubah {
    public static void main(String[] args) {
        final int batas = 10;
        batas = 20;
        System.out.println(batas);
    }
}

KonstantaFinal.java

Unduh berkas
java
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));
    }
}