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:
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:
diskon di dalam blok = 20
putaran ke-1, total = 100
putaran ke-2, total = 100
putaran ke-3, total = 100
total di akhir = 100Bedah cakupannya baris demi baris:
- Baris 4 (
int total = 100;):totaldideklarasikan langsung di badanmain, sehingga cakupannya menaungi seluruh badan method — baris di dalamif, di dalamfor, hingga baris terakhir semuanya boleh membacatotal. - Baris 7-9 (
int diskon = 20; ...):diskonlahir dan berakhir di dalam blokif. Pemakaian di baris 8 sah karena masih satu blok; begitu kurung tutup}dilewati, namadiskonberhenti eksis. - Baris 11-13 (
for (int i = 1; ...)): variabel deklarasiipada headerforhanya hidup untuk blok perulangan itu. Tiga putaran berbagi satuiyang sama; setelah perulangan selesai, namaitidak dapat dipakai lagi dimain.
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:
parameter batas = 75
field batas = 50
lokal batas = 99
field batas = 50Hasil 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 #
- JLS SE25 §6.3: Scope of a Declaration
- JLS SE25 §14.4.2: Scope of Declarations of Local Variables
- dev.java: Belajar Java
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
BayanganVariabel.java
Unduh berkaspublic 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 berkaspublic 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 berkaspublic 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);
}
}