Setiap variabel di Java punya wilayah kekuasaan sendiri: daerah teks program tempat nama variabel itu dapat dipakai, yang dinamai scope atau cakupan. Di dalam method, cakupan berlapis-lapis — variabel lokal milik seluruh badan method, variabel di dalam blok if atau for hanya hidup di bloknya, dan parameter hanya hidup selama satu pemanggilan. Salah mengira batas cakupan adalah sumber error kompilasi yang sangat sering muncul, biasanya berwujud cannot find symbol padahal variabel “tadi masih ada”. Pada Chapter ini kita petakan aturan cakupan di dalam method, bedah kasus variabel yang keluar dari bloknya, lalu pelajari shadowing — kondisi nama baru sengaja menaungi nama lama.

Cakupan Variabel Lokal dan Blok #

Aturan dasarnya satu kalimat: variabel lokal terlihat mulai dari baris deklarasinya sampai kurung tutup blok yang menaunginya. Blok adalah kumpulan pernyataan di antara { dan } — badan method, blok if, blok for, semuanya blok. Variabel yang dideklarasikan di blok dalam tidak terlihat dari blok luar; sebaliknya variabel blok luar tetap terlihat di blok dalam. Program berikut memperagakan lapisan-lapisan itu:

java CakupanBlok.java
public class CakupanBlok {

    public static void main(String[] args) {
        int total = 100;                // cakupan: seluruh badan main

        if (total > 50) {
            int diskon = 20;            // cakupan: hanya di dalam blok if
            System.out.println("diskon di dalam blok = " + diskon);
        }

        for (int i = 1; i <= 3; i++) {  // i hidup hanya selama blok for
            System.out.println("putaran ke-" + i + ", total = " + total);
        }

        System.out.println("total di akhir = " + total);
    }
}

Output yang Dihasilkan:

text
diskon di dalam blok = 20
putaran ke-1, total = 100
putaran ke-2, total = 100
putaran ke-3, total = 100
total di akhir = 100

Bedah cakupannya baris demi baris:

  1. Baris 4 (int total = 100;): total dideklarasikan langsung di badan main, sehingga cakupannya menaungi seluruh badan method — baris di dalam if, di dalam for, hingga baris terakhir semuanya boleh membaca total.
  2. Baris 7-9 (int diskon = 20; ...): diskon lahir dan berakhir di dalam blok if. Pemakaian di baris 8 sah karena masih satu blok; begitu kurung tutup } dilewati, nama diskon berhenti eksis.
  3. Baris 11-13 (for (int i = 1; ...)): variabel deklarasi i pada header for hanya hidup untuk blok perulangan itu. Tiga putaran berbagi satu i yang sama; setelah perulangan selesai, nama i tidak dapat dipakai lagi di main.

Cakupan Parameter dan Pemisahan Antar Method #

Parameter mengikuti aturan yang sama dengan variabel lokal, dengan satu pengecualian penting: parameter lahir saat method dipanggil dan berakhir saat method selesai — cakupannya adalah seluruh badan method yang memilikinya. Konsekuensinya, dua method adalah dua dunia yang terpisah: variabel lokal metodeA tidak dapat dibaca metodeB sekalipun berada dalam satu class, dan dua pemanggilan berbeda atas method yang sama tidak berbagi parameter. Pertukaran data antar method harus eksplisit lewat argument dan return value — mekanisme yang sudah kita kuasai pada Chapter sebelumnya.

Program berikut melanggar kedua aturan itu sekaligus — membaca variabel lokal method lain, dan membaca variabel yang sudah keluar dari bloknya:

public class VariabelTakTerlihat {

    static void metodeA() {
        int rahasia = 42;
    }

    static void metodeB() {
        // rahasia adalah variabel lokal milik metodeA
        System.out.println(rahasia);
    }

    public static void main(String[] args) {
        if (args.length >= 0) {
            int diskon = 20;
        }

        // diskon sudah berada di luar cakupan blok if
        System.out.println(diskon);
    }
}

Compiler javac menolak dengan dua pesan error: cannot find symbol — satu untuk rahasia pada metodeB, satu untuk diskon pada main — masing-masing dilengkapi symbol: variable ... dan location: class VariabelTakTerlihat. Kata cannot find symbol bisa menyesatkan pembaca baru: variabelnya jelas pernah ditulis, tetapi pada lokasi pemakaian tersebut nama variabel memang sudah tidak lagi berada dalam cakupan, sehingga bagi compiler nama itu tidak dikenal.

Shadowing #

Shadowing terjadi ketika dua nama yang sama hidup bersamaan: nama yang dideklarasikan di cakupan dalam menaungi entri bernama sama di cakupan luar. Kasus paling lazimnya di Java adalah parameter atau variabel lokal yang kebetulan satu nama dengan field class. Program berikut sengaja memakai nama batas tiga peran sekaligus:

public class BayanganVariabel {

    // Field static milik class: terlihat dari seluruh method class ini
    static int batas = 50;

    static void ujiShadowing(int batas) {
        // Parameter batas menaungi field bernama sama
        System.out.println("parameter batas = " + batas);
        System.out.println("field    batas = " + BayanganVariabel.batas);
    }

    public static void main(String[] args) {
        ujiShadowing(75);

        int batas = 99;  // variabel lokal juga boleh menaungi field
        System.out.println("lokal    batas = " + batas);
        System.out.println("field    batas = " + BayanganVariabel.batas);
    }
}

Output yang Dihasilkan:

text
parameter batas = 75
field    batas = 50
lokal    batas = 99
field    batas = 50

Hasil eksekusinya menunjukkan dua nama batas hidup berdampingan tanpa saling menimpa nilai: parameter bernilai 75 dan lokal bernilai 99 sama-sama berhasil dicetak, sementara field tetap menyimpan 50. Field yang tertutup tetap dapat dijangkau dengan menyebut pemiliknya secara eksplisit — BayanganVariabel.batas untuk field static, atau this.batas untuk field instance pada method non-static. Shadowing yang tidak disengaja adalah sumber bug yang sulit dilacak, jadi praktik terbaiknya adalah memberi nama parameter dan variabel lokal yang berbeda dari nama field.

Pemahaman cakupan melengkapi satu fondasi lagi untuk menulis method yang sehat: variabel method seharusnya hanya hidup dan berpengaruh di wilayahnya sendiri. Fondasi berikutnya naik satu tingkat menjadi prinsip desain — method yang tidak menulis apa pun di luar dirinya, bekerja murni dari masukan ke keluaran. Prinsip itu bernama pure function, materi Chapter Pure Functions.

Referensi #

Berkas Sumber

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

BayanganVariabel.java

Unduh berkas
java
public class BayanganVariabel {

    // Field static milik class: terlihat dari seluruh method class ini
    static int batas = 50;

    static void ujiShadowing(int batas) {
        // Parameter batas menaungi field bernama sama
        System.out.println("parameter batas = " + batas);
        System.out.println("field    batas = " + BayanganVariabel.batas);
    }

    public static void main(String[] args) {
        ujiShadowing(75);

        int batas = 99;  // variabel lokal juga boleh menaungi field
        System.out.println("lokal    batas = " + batas);
        System.out.println("field    batas = " + BayanganVariabel.batas);
    }
}

CakupanBlok.java

Unduh berkas
java
public class CakupanBlok {

    public static void main(String[] args) {
        int total = 100;                // cakupan: seluruh badan main

        if (total > 50) {
            int diskon = 20;            // cakupan: hanya di dalam blok if
            System.out.println("diskon di dalam blok = " + diskon);
        }

        for (int i = 1; i <= 3; i++) {  // i hidup hanya selama blok for
            System.out.println("putaran ke-" + i + ", total = " + total);
        }

        System.out.println("total di akhir = " + total);
    }
}

VariabelTakTerlihat.java

Unduh berkas
java
public class VariabelTakTerlihat {

    static void metodeA() {
        int rahasia = 42;
    }

    static void metodeB() {
        // rahasia adalah variabel lokal milik metodeA
        System.out.println(rahasia);
    }

    public static void main(String[] args) {
        if (args.length >= 0) {
            int diskon = 20;
        }

        // diskon sudah berada di luar cakupan blok if
        System.out.println(diskon);
    }
}