โ˜• Java

Java Variables โ€” Types, Scope, var Keyword & Best Practices

Everything you need to know about Java Variables โ€” what they are, three types (local, instance, static), data types, default values, var keyword, final variables, constants, naming conventions, scope and lifetime, variable shadowing, and real-world production code examples.

๐Ÿ“…

Last Updated

March 2026

โฑ๏ธ

Read Time

20 min

๐ŸŽฏ

Level

Beginner

๐Ÿท๏ธ

Chapter

4 of 35

What is a Variable in Java?

A variable is a named container that holds a value in memory. When you declare a variable in Java, the JVM reserves a memory location, gives it a name, and associates a data type with it. The data type determines what kind of value the variable can hold โ€” a whole number, a decimal, a single character, a true/false flag, or a reference to an object.

Every variable in Java has three essential components: (1) Type โ€” what kind of data it stores (int, String, double, etc.). (2) Name โ€” the identifier used to access it (age, userName, totalPrice). (3) Value โ€” the actual data stored (25, "Alice", 99.99). Java is a statically typed language โ€” every variable's type is fixed at compile time and cannot change at runtime.

โ˜• JavaVariableBasics.java
public class VariableBasics {
    public static void main(String[] args) {

        // โ”€โ”€ Variable declaration and initialization โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        // Syntax: dataType variableName = value;

        int age = 25;                  // integer variable
        double price = 99.99;           // decimal variable
        char grade = 'A';               // single character
        boolean isActive = true;        // true or false
        String name = "Priya";         // text (String is a class, not primitive)

        // โ”€โ”€ Declaration without initialization โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        int score;           // Declared but not yet initialized
        // System.out.println(score); // โŒ Compile error: variable not initialized
        score = 95;          // Now initialized โ€” safe to use
        System.out.println(score);  // 95

        // โ”€โ”€ Multiple variables of same type โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        int x = 10, y = 20, z = 30;
        System.out.println(x + y + z);  // 60

        // โ”€โ”€ Reassigning a variable โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        int count = 1;
        count = 2;   // Reassigned โ€” old value 1 is gone
        count = 3;
        System.out.println(count);  // 3

        // โ”€โ”€ Printing variables โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        System.out.println("Name: " + name);       // Name: Priya
        System.out.println("Age: " + age);         // Age: 25
        System.out.println("Price: " + price);     // Price: 99.99
        System.out.println("Active: " + isActive); // Active: true
    }
}

Types of Variables in Java

Java classifies variables into three types based on where they are declared โ€” which determines their scope (where they can be accessed), lifetime (how long they exist in memory), and default values (what value they hold before explicit assignment).

1๏ธโƒฃ
Local Variables

Declared inside a method, constructor, or block. Scope is limited to that block โ€” cannot be accessed from outside. No default value โ€” must be initialized before use or the compiler will refuse to compile. Stored on the stack. Created when the method is called, destroyed when the method returns. Cannot have access modifiers (public, private, etc.).

2๏ธโƒฃ
Instance Variables (Non-static Fields)

Declared inside a class body but outside any method, without the static keyword. Each object (instance) of the class gets its own separate copy. Have default values โ€” 0 for numeric types, false for boolean, null for object references. Stored on the heap along with the object. Lifetime matches the object โ€” created when object is created, destroyed when object is garbage collected. Can have access modifiers.

3๏ธโƒฃ
Static Variables (Class Variables)

Declared inside a class body with the static keyword, outside any method. Only one copy exists for the entire class โ€” shared across all instances. Have default values like instance variables. Stored in the method area (class memory). Lifetime matches the class โ€” loaded when class is loaded, destroyed when JVM shuts down or class is unloaded. Accessed via ClassName.variableName. Can have access modifiers.

Local Variables โ€” Method-Level Variables

Local variables are declared inside a method, constructor, block (if, for, while, try), or lambda. They are the most commonly used variables in Java and have the tightest scope โ€” they exist only within the block they are declared in. The compiler does not assign default values to local variables โ€” using an uninitialized local variable is a compile-time error.

โ˜• JavaLocalVariables.java
public class LocalVariables {

    public void calculateTotal() {
        // โ”€โ”€ Basic local variable โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        int quantity = 5;          // Local to calculateTotal()
        double unitPrice = 150.0;  // Local to calculateTotal()
        double total = quantity * unitPrice;
        System.out.println("Total: " + total);  // Total: 750.0
    }  // quantity, unitPrice, total are destroyed here

    public void scopeDemo() {
        int outer = 10;  // Accessible throughout scopeDemo()

        if (outer > 5) {
            int inner = 20;  // Local to this if-block only
            System.out.println(outer + inner);  // 30 โ€” both accessible here
        }
        // System.out.println(inner);  // โŒ Compile error: inner out of scope

        for (int i = 0; i < 3; i++) {  // i is local to the for loop
            System.out.println("i = " + i);
        }
        // System.out.println(i);  // โŒ Compile error: i out of scope
    }

    public void uninitialized() {
        int x;  // Declared but not initialized
        // System.out.println(x);  // โŒ Compile error: variable x not initialized

        x = 42;  // Now initialized
        System.out.println(x);  // โœ… 42
    }

    public void conditionalInit() {
        int result;
        boolean condition = true;

        if (condition) {
            result = 100;
        }
        // System.out.println(result);
        // โŒ Compile error โ€” compiler cannot guarantee result was initialized
        // (even though condition is always true โ€” compiler doesn't evaluate)

        // โœ… Fix: initialize in all branches or give default
        int safeResult = 0;  // Default value
        if (condition) {
            safeResult = 100;
        }
        System.out.println(safeResult);  // 100
    }

    public static void main(String[] args) {
        LocalVariables lv = new LocalVariables();
        lv.calculateTotal();
        lv.scopeDemo();
        lv.uninitialized();
        lv.conditionalInit();
    }
}

Instance Variables โ€” Object-Level Fields

Instance variables (also called fields or non-static fields) are declared inside a class body but outside any method or block, without the static keyword. They represent the state of an object โ€” each object created from the class gets its own private copy of every instance variable. Changes to one object's instance variable do not affect another object's copy.

โ˜• JavaInstanceVariables.java
public class Student {

    // โ”€โ”€ Instance variables โ€” each Student object gets its own copy โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    String name;         // Default: null
    int age;             // Default: 0
    double gpa;          // Default: 0.0
    boolean isEnrolled;  // Default: false

    // โ”€โ”€ Constructor โ€” sets instance variables at creation โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    public Student(String name, int age, double gpa) {
        this.name = name;  // 'this' distinguishes instance var from param
        this.age  = age;
        this.gpa  = gpa;
        this.isEnrolled = true;  // Default for new students
    }

    // โ”€โ”€ Instance method โ€” accesses instance variables โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    public void displayInfo() {
        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
        System.out.println("GPA: " + gpa);
        System.out.println("Enrolled: " + isEnrolled);
    }

    public static void main(String[] args) {

        // โ”€โ”€ Each object has its OWN copy of instance variables โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        Student s1 = new Student("Priya", 20, 8.5);
        Student s2 = new Student("Rahul", 22, 7.8);

        s1.displayInfo();
        // Name: Priya | Age: 20 | GPA: 8.5 | Enrolled: true

        s2.displayInfo();
        // Name: Rahul | Age: 22 | GPA: 7.8 | Enrolled: true

        // โ”€โ”€ Changing s1's variable does NOT affect s2 โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        s1.gpa = 9.0;
        System.out.println("s1 GPA: " + s1.gpa);  // 9.0
        System.out.println("s2 GPA: " + s2.gpa);  // 7.8 โ€” unchanged

        // โ”€โ”€ Default values (no constructor called) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        Student s3 = new Student("", 0, 0.0);
        // Without explicit initialization in constructor,
        // int โ†’ 0, double โ†’ 0.0, boolean โ†’ false, String โ†’ null
    }
}

Static Variables โ€” Class-Level Shared Variables

Static variables (also called class variables) are declared with the static keyword inside a class body, outside any method. There is only one copy of a static variable โ€” shared by all instances of the class. If one object changes a static variable, the change is visible to all other objects. Static variables are ideal for data that belongs to the class as a whole, not to individual objects โ€” such as counters, configuration constants, and shared state.

โ˜• JavaStaticVariables.java
public class BankAccount {

    // โ”€โ”€ Static variable โ€” ONE copy shared by ALL BankAccount objects โ”€โ”€โ”€โ”€โ”€
    static int totalAccounts = 0;         // Tracks how many accounts exist
    static double interestRate = 6.5;     // Same rate for all accounts

    // โ”€โ”€ Instance variables โ€” each account has its own โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    String accountHolder;
    double balance;
    int accountNumber;

    public BankAccount(String holder, double initialBalance) {
        this.accountHolder = holder;
        this.balance       = initialBalance;
        totalAccounts++;                   // Increment shared counter
        this.accountNumber = totalAccounts; // Unique number per account
    }

    public static void main(String[] args) {

        System.out.println("Accounts: " + BankAccount.totalAccounts);  // 0

        BankAccount acc1 = new BankAccount("Priya", 50000.0);
        BankAccount acc2 = new BankAccount("Rahul", 75000.0);
        BankAccount acc3 = new BankAccount("Anita", 30000.0);

        // โ”€โ”€ Static variable accessed via class name (preferred) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        System.out.println("Total accounts: " + BankAccount.totalAccounts);  // 3

        // โ”€โ”€ Also accessible via instance (not recommended โ€” misleading) โ”€โ”€โ”€
        System.out.println(acc1.totalAccounts);  // 3 โ€” same value

        // โ”€โ”€ Changing static variable affects ALL instances โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        BankAccount.interestRate = 7.0;  // Rate change for all accounts
        System.out.println(acc1.interestRate);  // 7.0
        System.out.println(acc2.interestRate);  // 7.0 โ€” same, it's shared

        // โ”€โ”€ Instance variables remain independent โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        System.out.println(acc1.balance);  // 50000.0
        System.out.println(acc2.balance);  // 75000.0 โ€” different

        // โ”€โ”€ Account numbers assigned correctly โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        System.out.println(acc1.accountNumber);  // 1
        System.out.println(acc2.accountNumber);  // 2
        System.out.println(acc3.accountNumber);  // 3
    }
}

Local vs Instance vs Static โ€” Complete Comparison

Understanding the differences between the three variable types is fundamental to writing correct Java programs. The table below summarizes all key differences side by side.

AspectLocal VariableInstance VariableStatic Variable
Declared inInside method / blockInside class, outside methodInside class with static keyword
KeywordNoneNone (no static)static
Default valueโŒ None โ€” must initializeโœ… 0 / false / nullโœ… 0 / false / null
ScopeDeclaring block onlyEntire class (via this)Entire class + all instances
LifetimeMethod executionObject lifetimeClass lifetime (JVM session)
Memory locationStackHeap (with object)Method area (shared)
CopiesOne per method callOne per object instanceOne per class (shared by all)
Access modifierโŒ Not allowedโœ… public/private/protectedโœ… public/private/protected
Access viaVariable name directlythis.name or object.nameClassName.name (preferred)
Thread safetyโœ… Safe (stack-local)โš ๏ธ Not safe if sharedโš ๏ธ Not safe โ€” shared state
Use caseTemp computation, loop varsObject state / propertiesCounters, constants, shared config

Data Types for Variables

Every Java variable must have a declared type. Java has two categories of data types: primitive types โ€” the 8 built-in value types โ€” and reference types โ€” objects, arrays, and interfaces. The type determines what values the variable can hold and how much memory it occupies.

โ˜• JavaDataTypes.java
public class DataTypes {
    public static void main(String[] args) {

        // โ”€โ”€ PRIMITIVE TYPES โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

        // Integer types
        byte   b  = 100;          // 8-bit  | -128 to 127
        short  s  = 30000;         // 16-bit | -32,768 to 32,767
        int    i  = 2_000_000;     // 32-bit | ~ยฑ2.1 billion (most common)
        long   l  = 9_000_000_000L; // 64-bit | very large numbers (suffix L)

        // Floating-point types
        float  f  = 3.14f;         // 32-bit | 7 decimal digits precision (suffix f)
        double d  = 3.14159265358; // 64-bit | 15-16 decimal digits (most common)

        // Character type
        char   c  = 'A';           // 16-bit | single Unicode character
        char   c2 = 65;            // Also 'A' โ€” stored as Unicode code point
        char   c3 = '\u0041';      // Also 'A' โ€” Unicode escape

        // Boolean type
        boolean flag = true;       // true or false only

        // โ”€โ”€ REFERENCE TYPES โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

        // String โ€” most common reference type
        String name = "Tech Sustainify";

        // Array
        int[] scores = {95, 87, 72};
        String[] cities = {"Delhi", "Mumbai", "Bangalore"};

        // Object
        Object obj = new Object();

        // โ”€โ”€ Numeric separators (Java 7+) โ€” readability โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        int million  = 1_000_000;       // Same as 1000000
        long billion = 1_000_000_000L;   // Same as 1000000000L
        double pi    = 3.141_592_653;    // Same as 3.141592653

        // โ”€โ”€ Type sizes and ranges โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        System.out.println("int max: "    + Integer.MAX_VALUE);  // 2147483647
        System.out.println("long max: "   + Long.MAX_VALUE);     // 9223372036854775807
        System.out.println("double max: " + Double.MAX_VALUE);   // 1.7976...E308
    }
}
TypeSizeRange / ValuesDefaultExample
byte8-bit-128 to 1270byte b = 100;
short16-bit-32,768 to 32,7670short s = 500;
int32-bit-2,147,483,648 to 2,147,483,6470int i = 42;
long64-bit-9.2ร—10ยนโธ to 9.2ร—10ยนโธ0Llong l = 99L;
float32-bit~ยฑ3.4ร—10ยณโธ, 7 digits precision0.0ffloat f = 3.14f;
double64-bit~ยฑ1.7ร—10ยณโฐโธ, 15 digits precision0.0double d = 3.14;
char16-bit0 to 65,535 (Unicode)'\u0000'char c = 'A';
boolean1-bittrue or falsefalseboolean b = true;

Default Values of Variables

Java automatically assigns default values to instance variables and static variables when they are declared without initialization. Local variables do NOT get default values โ€” using them before initialization causes a compile-time error. Understanding default values is important because uninitialized instance fields quietly hold these defaults โ€” which can lead to subtle bugs if you forget to set them in a constructor.

โ˜• JavaDefaultValues.java
public class DefaultValues {

    // โ”€โ”€ Instance variables โ€” get default values automatically โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    byte    defaultByte;     // 0
    short   defaultShort;    // 0
    int     defaultInt;      // 0
    long    defaultLong;     // 0L
    float   defaultFloat;    // 0.0f
    double  defaultDouble;   // 0.0
    char    defaultChar;     // '\u0000' (null character)
    boolean defaultBoolean;  // false
    String  defaultString;   // null
    int[]   defaultArray;    // null

    public void printDefaults() {
        System.out.println("byte:    " + defaultByte);     // 0
        System.out.println("short:   " + defaultShort);    // 0
        System.out.println("int:     " + defaultInt);      // 0
        System.out.println("long:    " + defaultLong);     // 0
        System.out.println("float:   " + defaultFloat);    // 0.0
        System.out.println("double:  " + defaultDouble);   // 0.0
        System.out.println("char:    " + defaultChar);     // (empty)
        System.out.println("boolean: " + defaultBoolean);  // false
        System.out.println("String:  " + defaultString);   // null
        System.out.println("array:   " + defaultArray);    // null
    }

    public static void main(String[] args) {
        new DefaultValues().printDefaults();

        // โ”€โ”€ Local variables โ€” NO default value โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        int localInt;
        // System.out.println(localInt);  // โŒ Compile error

        String localStr;
        // System.out.println(localStr);  // โŒ Compile error

        // โœ… Must initialize before use
        int safeLocal = 0;
        System.out.println(safeLocal);  // 0
    }
}

var Keyword โ€” Local Variable Type Inference (Java 10+)

Java 10 introduced local variable type inference via the var keyword. Instead of writing the explicit type, you write var and the compiler infers the type from the right-hand side expression. var is not a dynamic type โ€” the variable is still statically typed at compile time, the type is just written by the compiler instead of you. This reduces verbosity for long generic types while keeping full type safety.

โ˜• JavaVarKeyword.java
import java.util.*;
import java.util.stream.*;

public class VarKeyword {
    public static void main(String[] args) {

        // โ”€โ”€ Basic var usage โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        var name    = "Priya";       // Inferred: String
        var age     = 25;             // Inferred: int
        var price   = 99.99;          // Inferred: double
        var active  = true;           // Inferred: boolean

        System.out.println(name + " is " + age); // Priya is 25

        // โ”€โ”€ var shines with long generic types โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        // Without var:
        HashMap<String, List<Integer>> oldStyle = new HashMap<String, List<Integer>>();

        // With var โ€” much cleaner:
        var map = new HashMap<String, List<Integer>>();
        // Inferred: HashMap<String, List<Integer>>

        var numbers = new ArrayList<String>();
        // Inferred: ArrayList<String>
        numbers.add("Delhi");
        numbers.add("Mumbai");

        // โ”€โ”€ var in for-each loop โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        for (var city : numbers) {
            System.out.println(city.toUpperCase()); // city is String
        }

        // โ”€โ”€ var in traditional for loop โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        for (var i = 0; i < 3; i++) {  // i is int
            System.out.println(i);
        }

        // โ”€โ”€ var with streams โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        var result = numbers.stream()
                            .filter(s -> s.startsWith("D"))
                            .collect(Collectors.toList());
        System.out.println(result);  // [Delhi]

        // โ”€โ”€ RESTRICTIONS โ€” where var CANNOT be used โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        // โŒ var without initializer
        // var x;  // Compile error: cannot infer type

        // โŒ var with null initializer
        // var obj = null;  // Compile error: cannot infer type from null

        // โŒ var is LOCAL ONLY โ€” not for fields or method params
        // (shown in class-level code below)
    }

    // โŒ var NOT allowed as field type
    // var fieldName = "test";  // Compile error

    // โŒ var NOT allowed as method parameter
    // void process(var input) { }  // Compile error

    // โŒ var NOT allowed as return type
    // var getValue() { return 42; }  // Compile error
}

final Variables & Constants

The final keyword applied to a variable means it can be assigned only once. After the first assignment, any attempt to reassign it causes a compile-time error. For primitive final variables, the value itself is constant. For reference final variables, the reference is fixed โ€” you cannot point it to a different object โ€” but the object's internal state can still be modified. Constants in Java are declared as public static final and named in UPPER_SNAKE_CASE.

โ˜• JavaFinalVariables.java
import java.util.ArrayList;
import java.util.List;

public class FinalVariables {

    // โ”€โ”€ Constants โ€” public static final โ€” class-level constants โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    public static final double PI          = 3.14159265358979;
    public static final int    MAX_RETRIES = 3;
    public static final String APP_NAME    = "Tech Sustainify";

    // โ”€โ”€ Final instance variable โ€” must be set in constructor โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    private final String username;
    private final int    userId;

    public FinalVariables(String username, int userId) {
        this.username = username;  // Assigned once in constructor
        this.userId   = userId;
        // this.username = "other"; // โŒ Compile error: already assigned
    }

    public static void main(String[] args) {

        // โ”€โ”€ Final local variable โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        final int MAX_SCORE = 100;
        // MAX_SCORE = 200;  // โŒ Compile error: cannot assign to final
        System.out.println("Max score: " + MAX_SCORE);

        // โ”€โ”€ Final primitive โ€” value is fixed โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        final double TAX_RATE = 0.18;
        double total = 500.0 * (1 + TAX_RATE);
        System.out.println("Total with tax: " + total);  // 590.0

        // โ”€โ”€ Final reference โ€” REFERENCE is fixed, object state is not โ”€โ”€โ”€โ”€
        final List<String> cities = new ArrayList<>();
        cities.add("Delhi");    // โœ… Allowed โ€” modifying the object
        cities.add("Mumbai");   // โœ… Allowed
        System.out.println(cities);  // [Delhi, Mumbai]

        // cities = new ArrayList<>(); // โŒ Compile error: cannot reassign final ref

        // โ”€โ”€ Constants accessed via class name โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        System.out.println(FinalVariables.PI);           // 3.14159265358979
        System.out.println(FinalVariables.MAX_RETRIES);  // 3
        System.out.println(FinalVariables.APP_NAME);     // Tech Sustainify

        // โ”€โ”€ var + final together (Java 10+) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        final var greeting = "Hello, Java!";
        System.out.println(greeting);  // Hello, Java!
        // greeting = "Bye";  // โŒ Compile error
    }
}

Naming Conventions โ€” Writing Readable Java Variable Names

Java has well-established naming conventions that every professional developer follows. These are not enforced by the compiler โ€” they are community standards that make code readable, maintainable, and consistent across teams and projects. Following them signals professionalism and makes code reviews much smoother.

๐Ÿ“Œ
Variables & Parameters โ€” camelCase

Start with a lowercase letter. Capitalize the first letter of each subsequent word. Examples: firstName, totalAmount, isActive, customerAge, invoiceTotal, maxRetryCount. Avoid abbreviations unless universally understood (url, id, html are fine; cstmr for customer is not). Single-letter names are only acceptable for loop counters (i, j, k) and short lambda parameters.

๐Ÿ“Œ
Constants โ€” UPPER_SNAKE_CASE

All static final variables use all uppercase letters with words separated by underscores. Examples: MAX_SIZE, DEFAULT_TIMEOUT, PI, MAX_RETRY_COUNT, BASE_URL, APP_VERSION. This naming instantly signals to any reader that the value is constant and shared โ€” a visual contract. Never use camelCase for constants.

๐Ÿ“Œ
Boolean Variables โ€” is / has / can Prefix

Boolean variables and methods should read as yes/no questions. Use prefixes: isActive, isEnrolled, hasPermission, canEdit, isEmpty, wasDeleted. This makes conditions read naturally: if (isActive), if (hasPermission). Avoid names like active or enrolled alone for booleans โ€” they are ambiguous.

๐Ÿ“Œ
Valid Identifier Rules

Must start with a letter (a-z, A-Z), underscore (_), or dollar sign ($). Cannot start with a digit. Cannot be a Java keyword (int, class, return, static, etc.). Can contain letters, digits, underscores, dollar signs. Case-sensitive โ€” count and Count are different. Length limit is effectively unlimited. Avoid $ and _ as prefixes in application code โ€” reserved for generated/framework code conventions.

โ˜• JavaNamingConventions.java โ€” Good vs Bad
public class NamingConventions {

    // โ”€โ”€ โœ… GOOD naming โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    private String firstName;
    private int    customerAge;
    private double totalInvoiceAmount;
    private boolean isAccountActive;
    private boolean hasAdminPermission;

    public static final int    MAX_LOGIN_ATTEMPTS = 5;
    public static final String DEFAULT_CURRENCY   = "INR";
    public static final double GST_RATE           = 0.18;

    // โ”€โ”€ โŒ BAD naming โ€” avoid these โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    private String fn;            // โŒ Cryptic abbreviation
    private int    a;             // โŒ Meaningless single letter (not a loop)
    private double TotalAmount;   // โŒ Starts with uppercase (looks like class)
    private boolean active;       // โŒ Ambiguous for boolean โ€” use isActive
    private int    max_retries;   // โŒ snake_case for variable (use camelCase)

    // โŒ Constants with wrong naming
    private static final int maxSize = 100;    // โŒ Should be MAX_SIZE
    private static final double pi = 3.14;    // โŒ Should be PI

    // โ”€โ”€ โœ… Valid but unusual identifiers (avoid in practice) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    int _count = 0;     // Valid but avoid leading underscore
    int $temp  = 0;     // Valid but $ is for generated code
    int i2     = 0;     // Valid โ€” digit not at start

    // โ”€โ”€ โŒ Invalid identifiers โ€” compile error โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    // int 2count = 0;   // โŒ Starts with digit
    // int int = 0;      // โŒ Reserved keyword
    // int my-var = 0;   // โŒ Hyphen not allowed
    // int my var = 0;   // โŒ Space not allowed
}

Scope & Lifetime of Variables

Scope defines where in the code a variable can be accessed. Lifetime defines how long the variable exists in memory. These two concepts are closely related but distinct โ€” a variable's scope is determined by where it's declared in the source code, while its lifetime is a runtime concept tied to execution context and garbage collection.

โ˜• JavaScopeAndLifetime.java
public class ScopeAndLifetime {

    // โ”€โ”€ Class scope โ€” accessible anywhere in this class โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    static int classVar = 100;       // Static: lives as long as the class
    int instanceVar = 200;            // Instance: lives as long as the object

    public void methodScope() {
        // โ”€โ”€ Method scope โ€” accessible only in this method โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
        int methodVar = 300;
        System.out.println(classVar);    // โœ… Accessible
        System.out.println(instanceVar); // โœ… Accessible
        System.out.println(methodVar);   // โœ… Accessible

        if (methodVar > 100) {
            // โ”€โ”€ Block scope โ€” only inside this if block โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
            int blockVar = 400;
            System.out.println(blockVar);    // โœ… Accessible
            System.out.println(methodVar);   // โœ… Accessible (outer scope)
        }
        // System.out.println(blockVar); // โŒ blockVar out of scope here

        for (int i = 0; i < 3; i++) {
            // โ”€โ”€ Loop scope โ€” i exists only within the loop โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
            int loopBody = i * 10;  // New variable each iteration
            System.out.println(loopBody);
        }
        // System.out.println(i);       // โŒ i out of scope
        // System.out.println(loopBody); // โŒ loopBody out of scope

    }  // methodVar is destroyed here

    public void anotherMethod() {
        // System.out.println(methodVar); // โŒ methodVar not accessible here
        System.out.println(instanceVar);  // โœ… Instance var is accessible
        System.out.println(classVar);     // โœ… Static var is accessible
    }

    // โ”€โ”€ Try-with-resources scope โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    public void tryScope() {
        try {
            int tryVar = 10;
            System.out.println(tryVar);
        } catch (Exception e) {
            // tryVar not accessible here
        }
        // tryVar not accessible here
    }

    public static void main(String[] args) {
        ScopeAndLifetime obj = new ScopeAndLifetime();
        obj.methodScope();
        obj.anotherMethod();
    }
}

Variable Shadowing โ€” When Inner Hides Outer

Variable shadowing occurs when a variable declared in an inner scope has the same name as a variable in an outer scope. The inner variable shadows (hides) the outer one within its scope. In Java, a local variable can shadow an instance variable โ€” the local variable takes precedence inside the method. The this keyword is used to explicitly refer to the instance variable when both exist in scope.

โ˜• JavaVariableShadowing.java
public class VariableShadowing {

    // Instance variable
    int value = 100;
    String name = "Instance Name";

    public void shadowDemo() {
        // Local variable shadows instance variable
        int value = 200;  // Shadows this.value

        System.out.println(value);        // 200 โ€” local variable
        System.out.println(this.value);   // 100 โ€” instance variable via 'this'
    }

    // โ”€โ”€ Most common shadowing: constructor/method parameter vs field โ”€โ”€โ”€โ”€โ”€
    public VariableShadowing(String name) {
        // Parameter 'name' shadows instance field 'name'
        System.out.println(name);       // Parameter value (passed in)
        System.out.println(this.name);  // Instance field: "Instance Name"

        // โœ… Correct assignment using this
        this.name = name;  // Assigns parameter value to instance field
    }

    // โ”€โ”€ Block-level shadowing โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    public void blockShadow() {
        int x = 10;  // Outer local

        for (int i = 0; i < 3; i++) {
            // โŒ Cannot re-declare x inside โ€” Java does not allow local-to-local
            // int x = 20;  // Compile error: variable x already defined
            // Note: Java prevents shadowing LOCAL with another LOCAL in same method
            // But a local CAN shadow an INSTANCE variable (shown above)
        }
    }

    // โ”€โ”€ Static context โ€” no 'this' available โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    static int count = 0;

    public static void staticShadow() {
        int count = 99;  // Shadows static field
        System.out.println(count);                         // 99 โ€” local
        System.out.println(VariableShadowing.count);       // 0 โ€” static field
    }

    public static void main(String[] args) {
        VariableShadowing obj = new VariableShadowing("Constructor Param");
        obj.shadowDemo();
        staticShadow();
    }
}

Common Mistakes & Pitfalls โ€” Variable Bugs That Fool Everyone

These are the most common variable-related mistakes in Java โ€” frequently seen in beginner code and surprisingly also in experienced developer codebases under time pressure.

โ˜• JavaVariableMistakes.java
// โŒ MISTAKE 1: Using uninitialized local variable
int score;
// System.out.println(score);  // Compile error: variable score not initialized
// โœ… Fix: initialize before use
int safeScore = 0;

// โŒ MISTAKE 2: int overflow โ€” result wraps around silently
int max = Integer.MAX_VALUE;  // 2147483647
int overflow = max + 1;       // -2147483648 โ€” silent wrap, no exception!
System.out.println(overflow); // -2147483648
// โœ… Fix: use long for large numbers
long safeValue = (long) max + 1;  // 2147483648 โ€” correct

// โŒ MISTAKE 3: Integer division truncates โ€” losing decimal part
int a = 7, b = 2;
double result = a / b;         // 3.0 โ€” NOT 3.5! Division done as int
System.out.println(result);    // 3.0
// โœ… Fix: cast one operand to double
double correct = (double) a / b;  // 3.5

// โŒ MISTAKE 4: Confusing = (assignment) with == (comparison)
int x = 5;
// if (x = 10) { }  // Compile error: int cannot be used as boolean
// โœ… Use == for comparison
if (x == 10) { System.out.println("ten"); }

// โŒ MISTAKE 5: float precision โ€” unexpected decimal behavior
float f = 0.1f + 0.2f;
System.out.println(f);          // 0.3 (might show 0.3 or 0.30000001)
// โœ… Use double for better precision; use BigDecimal for exact money calculations

// โŒ MISTAKE 6: Accessing static variable via instance โ€” misleading
// BankAccount acc = new BankAccount();
// acc.interestRate = 7.0;  // Misleads readers โ€” looks like instance field
// โœ… Fix: BankAccount.interestRate = 7.0;

// โŒ MISTAKE 7: char arithmetic surprise
char c = 'A';
System.out.println(c + 1);    // 66 โ€” int result, not 'B'
System.out.println((char)(c + 1)); // 'B' โ€” must cast back to char

// โŒ MISTAKE 8: Forgetting L suffix for large long literals
// long bigNum = 10000000000;    // Compile error: int literal out of range
long bigNum = 10_000_000_000L;   // โœ… Correct with L suffix

// โŒ MISTAKE 9: Comparing strings with == instead of .equals()
String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1 == s2);       // false โ€” different objects
System.out.println(s1.equals(s2));  // true โœ… โ€” compare content

Bad Practices & Anti-Patterns โ€” What Senior Developers Reject

These anti-patterns represent common misuses of variables in professional Java code. Each one makes code harder to read, maintain, or reason about.

๐Ÿšซ
Reusing the Same Variable for Different Purposes

Using one variable to hold different meanings at different points in a method โ€” int temp = calculateTax(); then later temp = processRefund(); โ€” makes the code impossible to understand. Declare a new variable with a meaningful name for each distinct value. Variable declarations are cheap; the confusion from reuse is expensive. This is sometimes called 'variable recycling' and it is universally rejected in code reviews.

๐Ÿšซ
Declaring All Variables at the Top of a Method

A legacy style from older languages: declaring all local variables at the top of a method regardless of where they are used. Modern Java practice is to declare variables as close as possible to their first use โ€” this keeps scope tight, makes the code easier to follow, and reduces the chance of accidental misuse. The compiler optimizes either way, so there is no performance reason to declare early.

๐Ÿšซ
Using Magic Numbers Instead of Named Constants

Writing if (retries > 3) or price * 1.18 instead of named constants MAX_RETRIES and GST_RATE. Magic numbers have no self-documenting meaning โ€” readers must guess what 3 or 1.18 means. When the value changes, you must hunt down every occurrence. Fix: declare public static final constants with descriptive names. The constant is written once, read everywhere, and changed in one place.

๐Ÿšซ
Overly Wide Scope โ€” Variables Declared Too Early

Declaring a variable outside a loop when it is only needed inside, or as an instance variable when it should be local. Wide scope increases the chance of accidental modification, makes thread-safety harder, and confuses readers about the variable's purpose. The principle of least scope: declare a variable in the smallest scope that correctly satisfies its use. If a variable is only needed inside an if-block, declare it inside the if-block.

๐Ÿšซ
Not Making Variables final When They Should Be

Failing to mark local variables and method parameters as final when they are never reassigned. Making variables final communicates intent ('this value will not change'), prevents accidental reassignment bugs, and enables better compiler/JIT optimization. In modern Java codebases, many teams enforce that all variables that are never reassigned must be declared final. This is trivially enforced with tools like Checkstyle or SpotBugs.

๐Ÿšซ
Meaningless or Cryptic Variable Names

Names like d, tmp, x1, x2, val, data, obj, or result without context. These force every reader to mentally trace the code to understand what the variable holds. Meaningful names act as inline documentation: customerDiscountAmount explains itself; cda does not. The extra characters cost nothing at runtime โ€” the compiler optimizes away names. Invest in names โ€” they are the most read part of any codebase.

Real-World Production Code Examples โ€” Variables in Context

The following examples show how variable types, naming, scope, and final are applied in real enterprise Java and Spring Boot codebases.

โ˜• JavaOrderService.java โ€” Variables in a Service Class
package com.techsustainify.service;

import java.util.Objects;

@Service
public class OrderService {

    // โ”€โ”€ Constants โ€” static final, UPPER_SNAKE_CASE โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    private static final double GST_RATE          = 0.18;
    private static final int    MAX_ITEMS_PER_ORDER = 50;
    private static final String DEFAULT_CURRENCY   = "INR";

    // โ”€โ”€ Static variable โ€” shared counter โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    private static int totalOrdersProcessed = 0;

    // โ”€โ”€ Instance variables โ€” injected dependencies โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    private final OrderRepository orderRepository;
    private final NotificationService notificationService;

    // โ”€โ”€ Constructor injection with requireNonNull โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    public OrderService(OrderRepository orderRepository,
                        NotificationService notificationService) {
        this.orderRepository    = Objects.requireNonNull(orderRepository);
        this.notificationService = Objects.requireNonNull(notificationService);
    }

    // โ”€โ”€ Method with local variables โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    public double calculateOrderTotal(Order order) {
        Objects.requireNonNull(order, "order must not be null");

        // Local variables โ€” declared close to use, named meaningfully
        final double subtotal    = order.getSubtotal();
        final double gstAmount   = subtotal * GST_RATE;
        final double totalAmount = subtotal + gstAmount;

        return totalAmount;
    }

    public boolean processOrder(Order order) {
        Objects.requireNonNull(order, "order must not be null");

        // Local boolean with descriptive name
        final boolean isValidOrder = order.getItems().size() <= MAX_ITEMS_PER_ORDER
                                    && order.getSubtotal() > 0;

        if (!isValidOrder) {
            return false;
        }

        // var for obvious types โ€” reduces verbosity
        var savedOrder = orderRepository.save(order);
        var customerId = savedOrder.getCustomerId();

        notificationService.sendConfirmation(customerId);
        totalOrdersProcessed++;  // Increment shared static counter

        return true;
    }

    public static int getTotalOrdersProcessed() {
        return totalOrdersProcessed;
    }
}
โ˜• JavaUserProfile.java โ€” Instance Variables with Proper Design
package com.techsustainify.model;

import java.time.LocalDate;
import java.util.Objects;

public class UserProfile {

    // โ”€โ”€ Constants โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    public static final int MIN_AGE          = 18;
    public static final int MAX_USERNAME_LEN = 50;

    // โ”€โ”€ Static variable โ€” shared across all instances โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    private static int totalUsersCreated = 0;

    // โ”€โ”€ Instance variables โ€” state of a single UserProfile โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    private final int    userId;        // Immutable after construction
    private final String username;      // Immutable after construction
    private String       email;         // Mutable โ€” can be updated
    private boolean      isActive;      // Boolean with is-prefix
    private boolean      hasVerifiedEmail;
    private LocalDate    dateOfBirth;
    private int          loginCount;    // Tracks login frequency

    public UserProfile(int userId, String username, String email) {
        this.userId   = userId;
        this.username = Objects.requireNonNull(username, "username required");
        this.email    = Objects.requireNonNull(email,    "email required");
        this.isActive = true;
        this.hasVerifiedEmail = false;
        this.loginCount = 0;
        totalUsersCreated++;
    }

    // โ”€โ”€ Method with local variables โ€” tight scope โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
    public boolean isEligibleForPremium() {
        final int MIN_LOGINS = 10;
        final boolean meetsLoginThreshold = loginCount >= MIN_LOGINS;
        final boolean isVerified = hasVerifiedEmail && isActive;
        return meetsLoginThreshold && isVerified;
    }

    public void recordLogin() {
        if (!isActive) return;

        // Local variable for intermediate calculation
        var today = LocalDate.now();  // var โ€” type obvious from method name
        loginCount++;
        System.out.println(username + " logged in on " + today);
    }

    // Getters / setters omitted for brevity
    public static int getTotalUsersCreated() { return totalUsersCreated; }
}

Variable Type Decision Flowchart

When writing Java code, use this decision process to choose the correct variable type โ€” getting this right prevents scope leaks, unintended sharing, and subtle bugs.

๐Ÿ“ฆ Need to store a valueWhat kind of variable should I use?
Start
โ“ Shared across ALL instances?One copy for the entire class?
YES โ€” shared
โœ… Static Variablestatic dataType name; โ€” class-level
Check if constant
โ“ Value never changes?A constant โ€” no reassignment?
YES โ€” constant
โœ… Constantstatic final โ€” UPPER_SNAKE_CASE
โ“ Needed only inside a method/block?Temp result, loop counter, calculation?
YES โ€” method-only
โœ… Local VariabledataType name = value; โ€” must initialize
โœ… Instance VariableObject state โ€” each instance gets own copy

Code Execution Flow โ€” from source to output

Java Variables Interview Questions โ€” Beginner to Advanced

These questions are consistently asked in Java developer interviews at all levels โ€” from campus placements to senior engineer rounds. Variable types, scope, and the var keyword are frequently tested topics.

Practice Questions โ€” Test Your Java Variables Knowledge

Challenge yourself with these practice questions. Attempt each independently before reading the answer โ€” active recall is proven to be 2โ€“3x more effective than passive reading.

1. Will this compile? If not, why? public void calculate() { int a; int b = 10; int c = a + b; System.out.println(c); }

Easy

2. What is the output? public class Counter { static int count = 0; int id; public Counter() { count++; id = count; } public static void main(String[] args) { Counter c1 = new Counter(); Counter c2 = new Counter(); Counter c3 = new Counter(); System.out.println(c1.id); System.out.println(c2.id); System.out.println(Counter.count); } }

Easy

3. What is the output? Explain the shadowing. public class Shadow { int x = 50; public void display() { int x = 100; System.out.println(x); System.out.println(this.x); } public static void main(String[] args) { new Shadow().display(); } }

Easy

4. What is wrong? Fix it. public double calculateArea(double radius) { final double result; if (radius > 0) { result = Math.PI * radius * radius; } return result; }

Medium

5. Rewrite using var where appropriate: ArrayList<HashMap<String, List<Integer>>> data = new ArrayList<HashMap<String, List<Integer>>>(); HashMap<String, List<Integer>> entry = new HashMap<String, List<Integer>>(); List<Integer> values = new ArrayList<Integer>();

Medium

6. What is the output? Explain integer overflow. public class Overflow { public static void main(String[] args) { int max = Integer.MAX_VALUE; System.out.println(max); System.out.println(max + 1); long safe = (long) max + 1; System.out.println(safe); } }

Medium

7. Identify all variable types and issues: public class Employee { String department; static String companyName = "Tech Corp"; public double calculateBonus(double salary) { double rate; double bonus = salary * rate; return bonus; } }

Hard

8. What is the output? Explain why. public class FinalTest { public static void main(String[] args) { final int x = 10; final int y = 20; final int sum = x + y; System.out.println(sum); final StringBuilder sb = new StringBuilder("Hello"); sb.append(" Java"); System.out.println(sb); // sb = new StringBuilder("New"); // What happens here? } }

Hard

Conclusion โ€” Variables: The Foundation of Every Java Program

Variables are the most fundamental building block of any Java program โ€” every computation, every piece of state, every result flows through them. Understanding the three types โ€” local, instance, and static โ€” and choosing the right one for each situation is a core Java skill. Local variables for temporary computation, instance variables for object state, static variables for class-wide shared data or constants.

Professional Java code treats variable design as a first-class concern: tight scope (declare where needed, not at the top), meaningful names (no magic numbers, no cryptic abbreviations), final where possible (signal immutability, prevent reassignment bugs), and correct types (long for large numbers, double for decimals, boolean with is/has prefix). These habits cost nothing at runtime but make code dramatically more readable, maintainable, and bug-resistant.

ConceptTool / KeywordKey Rule
Local variableDeclared in method/blockNo default value โ€” must initialize
Instance variableDeclared in class, no staticDefault 0/false/null โ€” per object copy
Static variablestatic keyword in classOne shared copy โ€” access via ClassName
Constantpublic static final + UPPER_SNAKE_CASEAssign once โ€” never change
Type inferencevar (Java 10+)Local only โ€” type still static
final variablefinal keywordAssign once โ€” primitive or reference
Naming โ€” variablescamelCasefirstName, totalAmount, isActive
Naming โ€” constantsUPPER_SNAKE_CASEMAX_SIZE, GST_RATE, DEFAULT_TIMEOUT
Default โ€” primitives0, 0.0, false, '\u0000'Instance/static only โ€” not local
Default โ€” objectsnullInstance/static only โ€” not local
Integer overflowUse long for large valuesint silently wraps โ€” no exception
Integer divisionCast to double first(double) a / b โ€” not a / b

Your next step: Java Operators โ€” where you will use variables in arithmetic, comparison, logical, and bitwise expressions to build the computation logic of your programs. โ˜•

Frequently Asked Questions โ€” Java Variables