Variables are named memory slots with a type and value
Constants use final keyword and SCREAMING_SNAKE_CASE
Local variables must be initialized before use; instance/static get defaults
Java has 8 primitive types plus reference types for objects
Use final for values that must never change — compiler enforces it
Uninitialized local variables cause a compile-time error
✦ Definition~90s read
What is Variables and Constants in Java?
Java static variables (also called class variables) exist exactly once per class, not per instance. When you declare a field with static, that variable belongs to the class itself — all instances share the same memory location. This is fundamentally different from instance variables, where each object gets its own copy.
★
Think of a variable like a labelled box in your bedroom.
The primary reason static variables exist is to represent state that is truly global to the class: configuration constants, counters shared across all instances, or cached data that shouldn't be duplicated. In production systems, you'll see them used for things like connection pool sizes, application-wide flags, or the infamous static int counter that tracks how many times a method has been called across all threads.
The critical thing to understand — and where most bugs live — is that static variables are not thread-safe by default. A static int tradeCounter incremented with counter++ in a high-frequency trading system will corrupt data under load because the read-modify-write operation isn't atomic.
This is the classic race condition: two threads read the same value (say 42), both increment to 43, and you lose one increment. In practice, you either synchronize access, use AtomicInteger, or avoid mutable static state entirely. Many teams enforce a rule: static variables should be final unless you have a very good reason and a concurrency strategy.
Where static variables fit in the Java memory model: they live in the method area (or heap, depending on JVM version), not on the stack. They are initialized when the class is first loaded, before any instance is created. This means you can access them without creating an object — TradeCounter.totalTrades works even if no TradeCounter object exists.
The alternatives are instance variables (per-object state), local variables (method-scoped), or thread-local storage (ThreadLocal) when you need per-thread state without sharing. Don't use static variables for anything that should be scoped to a request, user session, or transaction — that's what dependency injection frameworks like Spring manage with prototype or request scopes.
Plain-English First
Think of a variable like a labelled box in your bedroom. You write a name on the outside — say 'socks' — and you can put things in, take them out, or swap the contents whenever you like. A constant is like a box that's been padlocked shut the moment you fill it — the label says 'date of birth' and nothing can ever change what's inside. Java works exactly the same way: variables hold data that can change, constants hold data that must never change.
Every program you have ever used — a weather app, a video game, a banking website — is constantly juggling data. A temperature reading, a player's score, a bank balance: all of it has to live somewhere in memory while the program is running. Without a way to name and store that data, writing even the simplest program would be impossible. Variables are the fundamental building blocks that make this work, and they show up in literally every Java file ever written.
Before variables existed, early programmers had to reference raw memory addresses — imagine telling someone to 'grab the thing at shelf 0x3F4A' instead of just saying 'grab the sugar'. Variables solve this by letting you give meaningful names to memory locations, so your code reads like English instead of a hardware manual. Constants take this one step further by letting you shout 'this value must NEVER change' — which prevents bugs that are notoriously hard to track down.
By the end of this article you'll know how to declare every kind of variable Java supports, understand the difference between primitive and reference types, lock down values with the final keyword, name things in a way that won't embarrass you in a code review, and dodge the three most common mistakes beginners make on day one.
What a Variable Actually Is — Memory, Names and Types
When your Java program runs, the operating system hands it a chunk of RAM to work with. A variable is just a named slot inside that RAM. You tell Java three things when you create one: what type of data it will hold, what you want to call it, and optionally what value to put in it right away.
The type matters because Java needs to know how much memory to reserve. A single character takes up far less space than a decimal number with ten digits. Java's 'primitive types' are the basic building blocks — whole numbers, decimal numbers, single characters, and true/false values. Think of them as different sized boxes in your warehouse.
Every variable has a lifecycle. It comes into existence when you declare it, holds whatever value you give it, and is destroyed when the block of code it lives in finishes running. Understanding this — called scope — will save you hours of debugging later.
You can declare a variable without giving it a value (declaration only), or declare it and give it a value at the same time (declaration + initialization). Both are valid, but Java will refuse to let you use a local variable before it's been given a value — it's stricter than most languages and that strictness is actually a gift.
VariableBasics.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
publicclassVariableBasics {
publicstaticvoidmain(String[] args) {
// --- DECLARATION ONLY ---// We reserve a slot called 'playerAge' that will hold a whole number (int).// It has no value yet — we cannot READ it until we assign one.int playerAge;
// --- DECLARATION + INITIALIZATION ---// We reserve the slot AND immediately put the value 25 inside it.int playerScore = 250;
// --- ASSIGNING AFTER DECLARATION ---// Now we fill the slot we created earlier.
playerAge = 25;
// --- DECIMAL NUMBERS use 'double' ---// 'double' stores numbers with a decimal point (64-bit precision).double itemPrice = 19.99;
// --- TRUE/FALSE values use 'boolean' ---// Only two possible values: true or false. Perfect for flags and conditions.boolean isLoggedIn = true;
// --- SINGLE CHARACTERS use 'char' ---// Note the SINGLE quotes — double quotes are for Strings, not chars.char grade = 'A';
// --- PRINTING the values to the console ---System.out.println("Player age: " + playerAge); // prints 25System.out.println("Player score: " + playerScore); // prints 250System.out.println("Item price: " + itemPrice); // prints 19.99System.out.println("Logged in: " + isLoggedIn); // prints trueSystem.out.println("Grade: " + grade); // prints A// --- CHANGING a variable's value ---// This is the whole point of a *variable* — it can vary.
playerScore = 500; // the old value 250 is gone, replaced by 500System.out.println("Updated score: " + playerScore); // prints 500
}
}
Output
Player age: 25
Player score: 250
Item price: 19.99
Logged in: true
Grade: A
Updated score: 500
The 8 Primitive Types at a Glance:
Java has exactly 8 primitive types: byte, short, int, long (whole numbers of increasing size), float, double (decimals), char (single character), and boolean (true/false). For 90% of everyday code, you'll reach for int, double, boolean, and char. Learn those four cold before worrying about the rest.
Production Insight
Accessing an uninitialised local variable is a compile-time error — Java's strictness saves you from runtime bugs.
Static and instance variables have default values, but relying on them silently leads to NullPointerExceptions when objects are null.
Rule: always initialise local variables; never rely on default values for object references.
Key Takeaway
A variable is a named memory slot with a type.
Local variables must be initialised before use.
Instance and static variables default to 0, false, or null.
thecodeforge.io
Java Static Variables and Race Conditions
Variables Constants Java
Variable Naming Rules and the Conventions That Get You Hired
Java has hard rules — break them and the code won't compile. Then there are conventions — break those and senior developers will wince during your code review.
The hard rules: A variable name must start with a letter, underscore _, or dollar sign $. It cannot start with a number. It cannot be a Java keyword like int, class, or return. Names are case-sensitive, so playerScore and playerscore are two completely different variables.
The convention: camelCase. Java developers universally use camelCase for variable names — start with a lowercase letter, then capitalize the first letter of every subsequent word. So accountBalance, numberOfLives, isEmailVerified. This isn't enforced by the compiler, but deviating from it signals immediately that you're new to the language.
Name for meaning, not brevity. A variable called n tells the next developer nothing. A variable called numberOfActiveUsers tells them everything. Yes, it's more typing. The five seconds you save typing a short name costs the next person (often future-you) five minutes of head-scratching.
Avoid abbreviations unless they're universally understood (url, id, html are fine). Avoid names that include the type, like intPlayerAge — that's a relic from the 1990s called Hungarian notation and it's considered noise in modern Java.
NamingConventions.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
publicclassNamingConventions {
publicstaticvoidmain(String[] args) {
// ✅ GOOD — camelCase, descriptive, instantly readableint numberOfStudentsEnrolled = 42;
double annualSalaryInDollars = 75000.00;
boolean isAccountSuspended = false;
String customerFullName = "MariaChen"; // String = text, not a primitive// ❌ BAD — compiles fine but will get you flagged in code review
int n = 42; // what does 'n' mean? Nobody knows.
double d = 75000.00; // is this salary? a measurement? a count?
boolean flag = false; // a 'flag' for WHAT?String s = "MariaChen"; // seriously, just... no.// ❌ ILLEGAL — these will cause a compile error// int 2ndPlayer = 5; // starts with a number — ILLEGAL// int player-score = 5; // hyphens not allowed — ILLEGAL// int class = 5; // 'class' is a reserved keyword — ILLEGAL// Printing the good variables so we can run thisSystem.out.println("Students enrolled: " + numberOfStudentsEnrolled);
System.out.println("Annual salary: $" + annualSalaryInDollars);
System.out.println("Account suspended: " + isAccountSuspended);
System.out.println("Customer name: " + customerFullName);
}
}
Output
Students enrolled: 42
Annual salary: $75000.0
Account suspended: false
Customer name: Maria Chen
Pro Tip: Name Booleans Like a Yes/No Question
Boolean variable names should read like a question you can answer with true or false. 'isUserAdmin', 'hasCompletedOnboarding', 'canEditDocument' — each one naturally reads as a yes/no question. If your boolean name doesn't work in a sentence like 'if (isUserAdmin)' then rename it.
Production Insight
A variable named temp in a critical financial calculation masked a bug for three sprints.
Descriptive names reduce cognitive load and prevent incorrect assumptions.
Rule: if you can't guess the variable's purpose from its name alone, rename it.
Key Takeaway
Follow camelCase for variables and SCREAMING_SNAKE_CASE for constants.
Names must be descriptive — n is never acceptable.
Avoid Hungarian notation; the type is declared elsewhere.
Constants With `final` — Locking Down Values That Must Never Change
Some values in your program should never change after they're set. The number of days in a week. The value of Pi. Your application's maximum upload size. The tax rate for a given region. If these values could accidentally be overwritten, bugs would be catastrophic — imagine a banking app where the interest rate could be silently changed mid-calculation.
Java's answer is the final keyword. Put final before a variable declaration and Java will throw a compile error the moment anyone tries to reassign it. The value is locked in for the lifetime of the program. These are called constants.
By convention, constant names use SCREAMING_SNAKE_CASE — all uppercase letters with underscores separating words. This visual distinction means any developer who reads MAX_LOGIN_ATTEMPTS instantly knows 'this value never changes', without having to scroll up to check the declaration.
You'll most often see constants declared with both static and final at the class level. static means the constant belongs to the class itself rather than to any one object — so there's only ever one copy of it in memory, shared everywhere. For now, just know that static final is the standard idiom for class-level constants and you'll see it constantly in production code.
ConstantsDemo.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
publicclassConstantsDemo {
// Class-level constants: static final + SCREAMING_SNAKE_CASE// These are defined outside main() so the whole class can access them.// The maximum number of times a user can attempt to log in before lockout.staticfinalint MAX_LOGIN_ATTEMPTS = 5;
// The sales tax rate — defined once, used everywhere in billing calculations.
static final double SALES_TAX_RATE = 0.08; // 8%// The name of the application — never changes at runtime.staticfinalString APP_NAME = "BudgetTracker Pro";
publicstaticvoidmain(String[] args) {
// Using the constants in real logicint currentLoginAttempts = 3;
double itemPrice = 49.99;
// Calculate the tax amount using our locked-in constantdouble taxAmount = itemPrice * SALES_TAX_RATE;
double totalPrice = itemPrice + taxAmount;
System.out.println("Welcome to " + APP_NAME);
System.out.println("Item price: $" + itemPrice);
System.out.println("Tax (" + (SALES_TAX_RATE * 100) + "%): $" + taxAmount);
System.out.println("Total: $" + totalPrice);
System.out.println("Login attempts remaining: " + (MAX_LOGIN_ATTEMPTS - currentLoginAttempts));
// ❌ Try uncommenting the line below — Java will REFUSE to compile.// MAX_LOGIN_ATTEMPTS = 10; // Error: cannot assign a value to final variable
}
}
Output
Welcome to BudgetTracker Pro
Item price: $49.99
Tax (8.0%): $3.9992
Total: $53.9892
Login attempts remaining: 2
Watch Out: `final` on Objects Isn't What You Think
final on a primitive locks the value permanently. But final on an object (like an ArrayList) only locks the reference — the object itself can still be modified. So a final List can still have items added to it. This trips up even intermediate developers. If you want a truly immutable object, that's a separate discussion involving immutable classes.
Production Insight
A final reference to a mutable object does not make the object immutable.
Using static final for constants reduces memory footprint — one per class instead of per instance.
Rule: always ask 'is the object itself immutable?' before declaring a reference final.
Key Takeaway
final prevents reassignment — not mutation.
Use SCREAMING_SNAKE_CASE for constants.
Pair final with static for class-level constants.
Variable Initialization: Default Values, Local vs Instance, and the 'var' Keyword
One of the most common sources of confusion is when variables get their first value. Java applies different rules depending on where a variable is declared.
Local variables — those inside a method, constructor, or block — must be explicitly assigned a value before they are used. The compiler will refuse to compile code that reads from an uninitialised local variable. This is a feature, not a bug: it prevents a whole class of bugs that plague languages like C or JavaScript.
Instance variables (fields) and static variables get default values automatically if you don't set them. Numbers default to 0 (0.0 for floating point), booleans default to false, and any object reference defaults to null. These defaults are often the source of subtle bugs — especially the null default for object references, which leads to NullPointerException at runtime.
Java 10 introduced the var keyword for local variables, allowing type inference. var tells the compiler 'figure out the type from the initialiser.' var count = 10; is equivalent to int count = 10;. But var is not a magic 'any type' — the type is still fixed at compile time, and you cannot reassign a different type. var is only allowed for local variables with an initializer, and using it incorrectly can make code harder to read.
InitializationAndVar.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
publicclassInitializationAndVar {
// Instance variable — gets default value 0.0double balance;
// Static variable — gets default value null for StringstaticString defaultName;
publicstaticvoidmain(String[] args) {
// Local variable — MUST be initialised before useint localCount;
// System.out.println(localCount); // Compile error: variable might not have been initialised
localCount = 10; // now it's safeSystem.out.println("Local count: " + localCount);
// Using var for type inference — only for local variables
var message = "HelloJava"; // String inferred
var price = 19.99; // double inferred// price = "not a number"; // Compile error: String can't be assigned to doubleSystem.out.println("Message: " + message);
System.out.println("Price: " + price);
// Instance and static variables: access through object or classInitializationAndVar obj = newInitializationAndVar();
System.out.println("Default balance: " + obj.balance); // prints 0.0System.out.println("Default name: " + defaultName); // prints null
}
}
Output
Local count: 10
Message: Hello Java
Price: 19.99
Default balance: 0.0
Default name: null
When to Use `var` — and When to Avoid It
Use var when the type is obvious from the initialiser, like var list = new ArrayList<String>(). Avoid var when the type is not clear, e.g. var result = someMethod() — it hurts readability. Also never use var for return types or method parameters; that requires var-like features from Java 10 for locals only.
Production Insight
A colleague once used var for a method call that returned a Map<String, List<Customer>> — the reader couldn't tell what the variable represented without digging into the method.
Instance fields defaulting to null cause NullPointerException when not properly initialised.
Rule: use var only when the type is immediately visible; always initialize local variables explicitly.
Key Takeaway
Local variables must be explicitly initialised.
Instance/static fields get defaults — but don't rely on them.
Use var only when the type is clear from context.
How to Choose Variable Initialization Style
IfVariable is local to a method
→
UseExplicitly initialize it before first use; do not rely on default.
IfVariable is an instance or static field
→
UseInitialize explicitly to avoid null defaults, unless you want a sentinel value.
IfLocal variable initializer makes type obvious (e.g. new ArrayList<>())
→
UseConsider using var for brevity.
IfInitializer is a complex expression or method call
→
UseUse explicit type for readability.
Where Variables Live — Local, Instance and Static Variables Explained
Not all variables are created equal — where you declare a variable determines who can use it, how long it lives, and what its default value is. Java has three distinct categories, and mixing them up is one of the most common sources of early confusion.
Local variables live inside a method. They're born when the method is called and destroyed when it returns. They have no default value — Java demands you initialize them before use, full stop.
Instance variables (also called fields) live inside a class but outside any method. Each object you create from that class gets its own private copy of these variables. They DO get default values: 0 for numbers, false for booleans, null for objects. They live as long as the object lives.
Static variables also live at the class level, but there's only ONE copy shared across every object of that class. Change it in one place and every object sees the new value. They're perfect for things like counting how many objects have been created, or storing shared configuration.
Think of it this way: static variables are like a whiteboard in a shared office (everyone sees the same thing), instance variables are like each person's personal notebook (each person has their own copy), and local variables are like a sticky note you write during a phone call and throw away when you hang up.
VariableScopeDemo.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
publicclassVariableScopeDemo {
// STATIC VARIABLE — one shared copy for the entire class.// Every time we create a new BankAccount, this counter goes up by 1.staticint totalAccountsCreated = 0;
// INSTANCE VARIABLES — each BankAccount object gets its own copies.// Java sets these to defaults: 0.0 for double, "" is NOT the default for// String — the default is null. We initialize explicitly to be safe.String accountHolderName;
double accountBalance;
// Constructor — called when we create a new BankAccount objectVariableScopeDemo(String holderName, double initialBalance) {
// LOCAL VARIABLE — only exists inside this constructor.// We use it temporarily before it disappears when the constructor ends.String welcomeMessage = "Account created for: " + holderName;
// Assigning values to the instance variablesthis.accountHolderName = holderName;
this.accountBalance = initialBalance;
// Incrementing the SHARED static counter
totalAccountsCreated++;
System.out.println(welcomeMessage); // use the local variable
}
voiddisplayBalance() {
// LOCAL VARIABLE — only lives during this method callString balanceReport = accountHolderName + " | Balance: $" + accountBalance;
System.out.println(balanceReport);
}
publicstaticvoidmain(String[] args) {
// Creating two separate account objectsVariableScopeDemo account1 = newVariableScopeDemo("James Okafor", 1500.00);
VariableScopeDemo account2 = newVariableScopeDemo("Priya Nair", 3200.50);
// Each object has its OWN instance variables
account1.displayBalance();
account2.displayBalance();
// But there is only ONE static variable — shared by bothSystem.out.println("Total accounts ever created: " + totalAccountsCreated);
}
}
Output
Account created for: James Okafor
Account created for: Priya Nair
James Okafor | Balance: $1500.0
Priya Nair | Balance: $3200.5
Total accounts ever created: 2
Default Values Only Apply to Instance and Static Variables:
Instance and static variables get safe defaults (0, false, null) if you don't initialize them. Local variables get nothing — Java leaves them in an undefined state and forces YOU to assign a value before use. This is why you get 'variable might not have been initialized' compile errors inside methods, but never at the class field level.
Production Insight
A static variable in a multithreaded environment without synchronisation causes race conditions.
Instance variables that are not properly initialised lead to NullPointerException when the object is used.
Rule: for shared mutable state, use Atomic classes or synchronisation; for instance fields, initialise in the constructor.
Key Takeaway
Static = one copy per class, shared across objects.
Instance = one copy per object.
Local = created per method call, destroyed on return.
The Constant Interface Is a Trap — Here Is What Happens at 2 AM
You inherit a codebase. Some senior before you decided to stuff all constants into an interface called CalculatorConstants. Classes implement it to get PI and UPPER_LIMIT without qualifying them. Looks clean in a code review. Then your team needs to change a constant value. You recompile only the interface because it's a microservice deploy. Now half your JVMs see the old value, half see the new one. The compiler inlined the constant into every referencing class at compile time. You now have a silent data corruption bug in production. That's why the constant interface pattern is considered harmful. Java's final modifier on a static field in the interface doesn't help — the compiler still inlines static final primitives and Strings. If you must share constants, use a non-instantiable utility class with a private constructor. Force recompilation of all consumers when the value changes. Your sleep schedule will thank you.
ConstantAntiPattern.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// io.thecodeforgepublicinterfaceCalculatorConstants {
doublePI = 3.14159265359;
double UPPER_LIMIT = 0x1.fffffffffffffP+1023;
}
// Don't do this:publicclassCalculatorimplementsCalculatorConstants {
publicdoublearea(double radius) {
return PI * radius * radius; // Compiler inlines PI at compile time
}
}
// Do this instead:publicfinalclassMathConstants {
privateMathConstants() {}
publicstaticfinaldoublePI = 3.14159265359;
publicstaticfinaldouble UPPER_LIMIT = 0x1.fffffffffffffP+1023;
}
Output
No direct output. Compiler behavior: static final primitives are inlined. Change PI in the interface, recompile only the interface — Calculator still uses the old 3.1415... silently.
Production Trap:
The JLS guarantees inlining for static final fields of primitive types and String. If you cannot recompile every consumer, use a method call instead: public static double pi() { return PI; }. The method call is never inlined across compilation units.
Key Takeaway
Never define constants in an interface. Use a final class with a private constructor. If the value can ever change, wrap it in a static method.
Enums Beat Constants Classes for Business Logic — Here Is Why
You see a Constants class with a hundred fields: MAX_RETRY_COUNT, ORDER_STATUS_PENDING, ORDER_STATUS_SHIPPED. Every service imports it. It becomes a dumping ground. Nobody knows which constant belongs where. The compiler inlines primitives across microservices. When you need to add a new order status, you touch the Constants class. Deploy a new version of order-service without recompiling fulfillment-service — and fulfillment-service still sees the old inlined value. The fix is an enum. Enums are not inlined. Enums carry behavior. OrderStatus.PENDING has a description, a next step, a timeout value. You can add a field, a method, a default implementation. The compiler treats enum constants as object references — they cannot be inlined across compilation units. You change the enum, recompile the enum JAR, and every consumer picks up the new value on restart. No silent inconsistency. Plus, your code reads like a domain language: if (order.getStatus() == OrderStatus.SHIPPED). Stop using public static final String for business states. Use enums. Your production incidents will drop.
A static final String ORDER_STATUS_SHIPPED = "SHIPPED" in a Constants class gets inlined. Change it in the JAR, but don't recompile the consumer — the consumer still sees the old string. An enum never gets inlined. Use enums for any value that represents a fixed set of business states.
Key Takeaway
Enums are not inlined across compilation units. For any constant that represents a finite set of domain values, use an enum — not a static final String or int.
● Production incidentPOST-MORTEMseverity: high
The Shared Counter That Crashed a Trading Platform
Symptom
Trade logs showed duplicate sequence numbers, and the daily trade count fluctuated randomly between runs. No crashes, but regulatory reports were wrong.
Assumption
The developer assumed that incrementing an int is atomic. In Java, count++ is three separate operations: read, add, write — not thread-safe.
Root cause
A static variable int tradeCounter = 0 was incremented via tradeCounter++ inside a method called by multiple threads. No synchronisation or atomic class used.
Fix
Replaced int with AtomicInteger and used incrementAndGet(). Alternatively, synchronised the increment method, but AtomicInteger is faster for simple counters.
Key lesson
Never assume single-line operations are atomic in Java.
Use AtomicInteger or synchronized for shared mutable state.
For constants that must be thread-safe, prefer final immutable values.
Production debug guideHow to diagnose common variable mistakes that slip through into runtime3 entries
Symptom · 01
NullPointerException when accessing an object field
→
Fix
Check if the variable is a class field that wasn't initialised, or a local variable that might be null. Add logging before the access point.
Symptom · 02
Incorrect calculations due to uninitialised local variable
→
Fix
This typically shows as a compile-time error. If you see a runtime value that seems random, check if the variable was reassigned unintentionally or if a default value (0 for ints) is being used instead of a real value.
Symptom · 03
Unexpected behaviour from shared static variables
→
Fix
Look for static fields that are modified without synchronisation. Use thread dumps to identify concurrent mutations.
★ Quick Debug: Variable IssuesIf a variable-related bug makes it to production, use these step-by-step commands to isolate the root cause quickly.
Null pointer exception (NPE)−
Immediate action
Identify the variable that is null. Use a debugger or add temporary print statements before the NPE line.
Commands
Add System.out.println("Variable: " + myVar) before the crash
Use IDE breakpoint and evaluate expression
Fix now
Initialise the variable properly or add a null check
Unexpected value in calculation+
Immediate action
Print all variables involved in the calculation at the point of use.
Commands
System.out.println("x = " + x + ", y = " + y)
Check the scope of variables — are they shadowed?
Fix now
Rename or refactor to avoid shadowing, ensure correct initialisation
Concurrent modification of shared variable+
Immediate action
Inspect thread dumps to see which threads are modifying the variable.
Commands
Use `jstack <pid>` to capture thread dump
Search for the variable name in the stack traces
Fix now
Add synchronisation or use Atomic classes
Aspect
Variable
Constant (final)
Can value change after assignment?
Yes — reassign any time
No — compile error if you try
Keyword used
None needed (just the type)
final keyword before the type
Naming convention
camelCase (e.g. playerScore)
SCREAMING_SNAKE_CASE (e.g. MAX_SCORE)
Typical use case
Data that changes: scores, names, counts
Fixed data: tax rates, limits, app config
Default value (instance/static)
0, false, or null depending on type
Same — but must be assigned exactly once
Enforced by compiler?
N/A — values flow freely
Yes — compiler blocks any reassignment attempt
Common location
Inside methods or as class fields
Class level, usually with static final
Key takeaways
1
A variable is a named memory slot
you declare it with a type, a name, and optionally a value. The type tells Java how much memory to reserve and what operations are legal on it.
2
The final keyword makes a variable a constant
Java will throw a compile error on any attempt to reassign it. Use SCREAMING_SNAKE_CASE and pair it with static at the class level for true shared constants.
3
Local variables (inside methods) have no default values
you MUST initialize them before use or the code won't compile. Instance and static variables do get defaults (0, false, null), but relying on null defaults silently is a path to NullPointerExceptions.
4
Naming is not optional style
using camelCase for variables, SCREAMING_SNAKE_CASE for constants, and genuinely descriptive names (numberOfActiveUsers not n) is what separates code that gets approved in review from code that gets sent back.
5
For shared mutable state across threads, synchronisation or atomic classes are required
a simple increment is not thread-safe.
Common mistakes to avoid
3 patterns
×
Using a local variable before initializing it
Symptom
You get a compile error: 'variable X might not have been initialized'. This happens when you declare a variable (e.g. int totalScore;) but forget to assign it a value before using it in a print or calculation.
Fix
Always assign an initial value at declaration, even if it's just zero: int totalScore = 0;.
×
Confusing `=` (assignment) with `==` (comparison)
Symptom
Writing if (playerScore = 100) instead of if (playerScore == 100) is a logic error. In Java, single = assigns a value; double == compares two values. Java will actually catch this specific case and throw a compile error since the result of an assignment isn't a boolean, but understanding the distinction early prevents subtle bugs in languages where this compiles silently.
Fix
Use == for equality checks, and = only for assignment. For boolean comparisons, consider using if (condition) directly.
×
Trying to reassign a `final` variable
Symptom
Declaring final int MAX_RETRIES = 3; and then later writing MAX_RETRIES = 5; causes a compile error: 'cannot assign a value to final variable MAX_RETRIES'.
Fix
Either remove final if the value needs to change, or rethink your design — maybe you actually want a regular variable. The error is a feature: it means Java caught your mistake before it became a runtime bug.
INTERVIEW PREP · PRACTICE MODE
Interview Questions on This Topic
Q01JUNIOR
What is the difference between a variable and a constant in Java, and ho...
Q02JUNIOR
What are the three types of variables in Java (local, instance, static),...
Q03SENIOR
If you declare a `final` reference variable pointing to an ArrayList, ca...
Q01 of 03JUNIOR
What is the difference between a variable and a constant in Java, and how do you declare each one?
ANSWER
A variable is a named memory location that can hold data, and its value can be changed after declaration. A constant is a variable that cannot be reassigned after initialization, declared using the final keyword. Variables use camelCase naming; constants use SCREAMING_SNAKE_CASE. Example: int age = 30; is a variable; final int MAX_AGE = 120; is a constant. Constants are often declared static final at the class level.
Q02 of 03JUNIOR
What are the three types of variables in Java (local, instance, static), how do they differ in terms of scope and lifetime, and which ones get default values?
ANSWER
Local variables are declared inside a method, constructor, or block. They exist only during method execution and must be explicitly initialised before use — no default values. Instance variables (fields) belong to each object instance and live as long as the object. They get default values (0, false, null). Static variables belong to the class itself, shared among all instances, and also get default values; they live until the program ends. Example: a static counter increments across all objects.
Q03 of 03SENIOR
If you declare a `final` reference variable pointing to an ArrayList, can you still add items to that list? Why or why not — and what does this tell you about what `final` actually guarantees?
ANSWER
Yes, you can still add items to the list. final on a reference variable only prevents reassignment of the reference itself—it does not make the object immutable. The reference always points to the same ArrayList object, but that object's internal state can change. This means final guarantees that the variable always refers to the same object, not that the object is constant. To make the list unmodifiable, you'd need Collections.unmodifiableList() or use an immutable collection from Java 9+.
01
What is the difference between a variable and a constant in Java, and how do you declare each one?
JUNIOR
02
What are the three types of variables in Java (local, instance, static), how do they differ in terms of scope and lifetime, and which ones get default values?
JUNIOR
03
If you declare a `final` reference variable pointing to an ArrayList, can you still add items to that list? Why or why not — and what does this tell you about what `final` actually guarantees?
SENIOR
FAQ · 4 QUESTIONS
Frequently Asked Questions
01
What is the difference between int and double in Java?
int stores whole numbers only (like 5, -200, 1000) and uses 32 bits of memory. double stores numbers with a decimal point (like 3.14, -0.5, 99.99) and uses 64 bits. Use int for counts and indexes, and double for measurements, prices, or anything that needs a fractional part.
Was this helpful?
02
Can a Java variable name start with a number?
No — this is a hard rule enforced by the compiler. Variable names must start with a letter, an underscore _, or a dollar sign $. Starting with a number (like 2ndPlace) will give you a compile error immediately. In practice, just start every variable name with a lowercase letter and you'll never hit this issue.
Was this helpful?
03
What happens if I don't initialize an instance variable in Java?
Java assigns it a safe default value automatically. Numbers default to 0 (or 0.0 for double/float), booleans default to false, and any object reference defaults to null. This only applies to instance and static variables — local variables inside methods have no default and must be explicitly initialized before you use them.
Was this helpful?
04
Can I use `var` for method parameters or return types?
No. var is only allowed for local variable declarations with an initializer. It cannot be used for method parameters, return types, fields, or catch parameters. The type is inferred at compile time and remains fixed.