Skip to content

Java Variable Scope

Updated 8 min read Aimerscrew

Have you ever seen the error cannot find symbol for a variable you know you declared? The cause is almost always scope. Java variable scope decides where in your code a variable can be seen and used, and how long it lives. In this lesson, you'll learn about local variables, block scope inside loops and if statements, parameter scope, a first look at shadowing, and what happens to variables on the call stack.

🌍 Real-life example

A hotel key card opens only your room, and only during your stay. Guests in other rooms have their own cards, which may even have the same room-number format, but they don't open your door. When you check out, the card stops working. Variables are similar: each one works only inside its own "room" of code (its scope) and only while that code is running (its lifetime).

What is variable scope in Java?

The scope of a variable is the region of code where its name can be used. In Java, scope is decided by curly braces: a variable is visible from the line where it's declared down to the closing } of the block that contains it. Outside that region, the name simply doesn't exist.

A closely related idea is lifetime: how long the variable's value actually exists in memory while the program runs. For the variables in this lesson, both end at the same closing brace.

Local variables: each method has its own

A variable declared inside a method is a local variable. Only that method can see it. Two methods can even use the same name without any conflict, because each name lives in a different scope.

public class Checkout {
    public static void main(String[] args) {
        double total = 49.99;
        printReceipt();
        System.out.println("main's total: " + total);
    }

    public static void printReceipt() {
        double total = 12.50;   // a different variable that happens to share the name
        System.out.println("printReceipt's total: " + total);
    }
}
printReceipt's total: 12.5
main's total: 49.99

If printReceipt tried to use main's variable without declaring its own, the compiler would report error: cannot find symbol. To share a value with another method, pass it as an argument and send results back with return.

What is block scope in Java?

A block is any group of statements inside curly braces: the body of an if, a loop, or just a pair of braces on their own. A variable declared inside a block exists only inside that block, including any blocks nested within it.

public class Thermostat {
    public static void main(String[] args) {
        int roomTemp = 17;

        if (roomTemp < 19) {
            int degreesToHeat = 19 - roomTemp;   // exists only inside this if
            System.out.println("Heating by " + degreesToHeat + " degrees");
        }

        // degreesToHeat can't be used here: its block has ended
        System.out.println("Room temperature was " + roomTemp);
    }
}
Heating by 2 degrees
Room temperature was 17

roomTemp is declared in main's block, so it's visible everywhere in main, including inside the if. degreesToHeat lives only between the if's braces.

Loop variables

The variable declared in a for loop header belongs to the loop. It disappears as soon as the loop ends:

for (int i = 0; i < 3; i++) {
    System.out.println(i);
}
System.out.println(i);   // error: cannot find symbol

If you need a value after the loop finishes, declare the variable before the loop. Here, found and position must outlive the loop, so they're declared outside it:

public class SeatFinder {
    public static void main(String[] args) {
        boolean[] taken = {true, true, false, true, false};
        boolean found = false;
        int position = -1;

        for (int seat = 0; seat < taken.length; seat++) {
            if (!taken[seat]) {
                found = true;
                position = seat;
                break;
            }
        }

        if (found) {
            System.out.println("First free seat: " + (position + 1));
        }
    }
}
First free seat: 3

Because each loop's variable vanishes when the loop ends, two loops one after the other can both use i without any problem. They're two separate variables in two separate scopes.

Can you declare the same variable name twice?

Not if the two scopes overlap. Inside a method, a block can't declare a local variable with the same name as one that's still in scope from an outer block:

int total = 0;
for (int i = 0; i < 3; i++) {
    int total = i;   // error: variable total is already defined in method main(String[])
}

Java forbids this on purpose, because it would be very confusing to have two totals alive at once. Sibling blocks, which don't overlap, are fine:

public class TwoLoops {
    public static void main(String[] args) {
        for (int i = 1; i <= 2; i++) {
            System.out.println("Morning class " + i);
        }
        for (int i = 1; i <= 2; i++) {
            System.out.println("Evening class " + i);
        }
    }
}
Morning class 1
Morning class 2
Evening class 1
Evening class 2

What is the scope of a method parameter?

A parameter's scope is the whole body of its method. It's created when the method is called, filled with the argument's value, and destroyed when the method returns. In every other way it behaves like a local variable declared on the first line.

public class Parking {
    public static void main(String[] args) {
        System.out.println(fee(3));
        System.out.println(fee(10));
    }

    public static int fee(int hours) {        // hours: visible in the whole method
        int rate = 4;                          // rate: visible from here to the end
        if (hours > 8) {
            int dailyCap = 30;                 // dailyCap: only inside this if
            return Math.min(hours * rate, dailyCap);
        }
        return hours * rate;
    }
}
12
30

Math.min returns the smaller of two numbers; you'll meet it properly in the Math class lesson.

A first look at shadowing

Besides local variables, a class can have variables declared outside any method, called fields. Every method in the class can see them. If a method declares a local variable with the same name as a field, the local one shadows (hides) the field inside that method:

public class Bakery {
    static String shopName = "Sunrise Bakery";   // a field

    public static void main(String[] args) {
        printSign();
        printPopUpSign();
    }

    public static void printSign() {
        System.out.println("Welcome to " + shopName);
    }

    public static void printPopUpSign() {
        String shopName = "Sunrise Pop-Up";      // shadows the field
        System.out.println("Welcome to " + shopName);
    }
}
Welcome to Sunrise Bakery
Welcome to Sunrise Pop-Up

Shadowing is legal, but it can cause confusing bugs. You'll learn about fields in classes and objects, about static fields in Java static, and how the this keyword lets you reach a shadowed field.

How long do local variables live? The call stack

Java keeps track of running methods using the call stack. Every time a method is called, Java pushes a new stack frame on top of the stack. The frame holds that call's parameters and local variables. When the method returns, its frame is removed, and all of its local variables disappear with it.

public class CallStackDemo {
    public static void main(String[] args) {
        double price = 80.0;
        double total = checkout(price);
        System.out.println("Total: " + total);
    }

    public static double checkout(double amount) {
        double shipping = 5.0;
        return addTax(amount + shipping);
    }

    public static double addTax(double subtotal) {
        double tax = subtotal * 0.10;
        return subtotal + tax;
    }
}
Total: 93.5
Animation of the call stack: main's frame holds price; calling checkout pushes a frame with amount and shipping; calling addTax pushes a frame with subtotal and tax; then addTax returns 93.5 and its frame is removed, checkout returns 93.5 and its frame is removed, leaving main with total = 93.5
Each call gets its own frame of local variables. When the method returns, the frame and its variables are gone.

This explains why a local variable never "remembers" its value between calls. Each call builds a fresh frame:

public class VisitCounter {
    public static void main(String[] args) {
        recordVisit();
        recordVisit();
        recordVisit();
    }

    public static void recordVisit() {
        int visits = 0;      // created fresh on every call
        visits++;
        System.out.println("Visits: " + visits);
    }
}
Visits: 1
Visits: 1
Visits: 1

To keep a running count, store the count in main and pass it in (and return the new value), or use a field once you've learned about them.

💡 Tip

Declare each variable in the smallest scope that works, as close as possible to where it's first used. Small scopes mean fewer names to keep in your head and fewer chances for one part of the code to accidentally change another's data.

Common mistakes with variable scope

1. Using a loop variable after the loop

The loop counter dies with the loop. Declare a separate variable before the loop if you need the value afterwards.

2. Declaring a variable inside an if, then using it outside

if (score > 100) {
    String badge = "Gold";
}
System.out.println(badge);   // error: cannot find symbol

Declare badge before the if (with a default such as "None") and assign it inside.

3. Expecting a local variable to remember its value

As VisitCounter showed, locals start over on every call.

4. Redeclaring a name in a nested block

Use the existing variable (total = i;) instead of declaring a new one (int total = i;).

Practice exercise

🏋️ Try it yourself

This program should add up a week of step counts and print the total and the average, but it doesn't compile. Find the scope problem and fix it.

int[] steps = {8200, 10450, 6300, 12000, 9100, 7400, 11050};
for (int i = 0; i < steps.length; i++) {
    int total = 0;
    total += steps[i];
}
System.out.println("Total: " + total);
System.out.println("Average: " + total / steps.length);
Show solution

total was declared inside the loop, so it doesn't exist after the loop (and it was reset to 0 on every lap). Move the declaration before the loop:

public class StepTracker {
    public static void main(String[] args) {
        int[] steps = {8200, 10450, 6300, 12000, 9100, 7400, 11050};
        int total = 0;
        for (int i = 0; i < steps.length; i++) {
            total += steps[i];
        }
        System.out.println("Total: " + total);
        System.out.println("Average: " + total / steps.length);
    }
}
Total: 64500
Average: 9214

What's next?

You now know how each method call gets its own stack frame. That's the key to understanding a method that calls itself. Next up: Java recursion.

Key takeaways

  • Scope is the region of code where a variable can be used; in Java it is set by curly braces.
  • Local variables belong to their method; other methods cannot see them, even if they use the same name.
  • Variables declared in an if block or loop exist only inside that block.
  • A parameter is visible throughout its method body.
  • You cannot redeclare a local variable name while the outer one is still in scope, but sibling blocks may reuse names.
  • Each method call gets a new stack frame; its local variables vanish when the method returns.
  • Declare variables in the smallest scope that works.

Frequently asked questions

What is variable scope in Java?

Scope is the part of the code where a variable's name can be used. A variable is in scope from its declaration until the closing brace of the block that contains it.

What is a local variable in Java?

A local variable is declared inside a method or block. It can only be used inside that method or block, and it is created again each time the method runs.

Why do I get "cannot find symbol" for a variable I declared?

Usually the variable is out of scope: it was declared inside a block, such as a loop or an if, and you are using it after that block ended, or it belongs to a different method.

Can two methods have variables with the same name?

Yes. Each method has its own scope, so a variable called total in one method is completely separate from a variable called total in another.

What is variable shadowing in Java?

Shadowing happens when a local variable or parameter has the same name as a field. Inside that scope, the name refers to the local variable and hides the field.