Declaring a variable takes one line, but three decisions hide in it: what type it is, whether it can change, and what it is called. Java gives you exactly one form of type inference — the keyword var — and it is narrower than most languages that offer the same idea.
How do you declare a variable?
A declaration states the type and the name; a separate statement may assign a value. Doing both at once is what you will write most of the time.
public class Variables {
public static void main(String[] args) {
int count; // declared, not yet initialised
count = 10; // assigned
String name = "Ada"; // declared and initialised
double balance = 42.50;
boolean active = true;
System.out.println(count + " " + name + " " + balance + " " + active);
}
}
Using a local variable before it is assigned is a compile error, not a runtime surprise. The compiler insists on definite assignment, so a value is always known when you read it — a guarantee you give up the moment you move to fields.
When should a value be final?
A variable declared final can be assigned once and then never changes. The convention is to put such values in UPPER_SNAKE_CASE, which signals to every reader that this is a constant rather than a value that happens not to change yet.
public class Limits {
static final int MAX_RETRIES = 3;
static final String API_ROOT = "https://api.example.com";
final double taxRate; // per-instance constant, set in the constructor
public Limits(double taxRate) {
this.taxRate = taxRate;
}
}
Three things make final worth using. The compiler stops you from reassigning a value that was meant to be fixed. The meaning of the constant is documented in one place instead of being implied by every usage. And because a final field is set exactly once, other threads see a stable value after construction without any synchronisation.
The static keyword is a separate idea: static means one copy shared by the class, final means that copy cannot change. A static final constant is the combination most constants want.
What does var actually do?
var asks the compiler to infer the type from the initialiser. The variable still has a fixed, concrete type — it is not a dynamic variable, and it cannot later hold a different type.
public class Inferred {
public static void main(String[] args) {
var name = "Ada"; // inferred as String
var count = 42; // inferred as int
var ratio = 0.75; // inferred as double
// name = 42; // does not compile: the type is fixed
System.out.println(name + " " + count + " " + ratio);
}
}
Three limits are worth remembering. var only works for local variables, never for fields, parameters or return types. It needs an initialiser — there is nothing to infer from otherwise. And when the initialiser is a literal, the inferred type can surprise you: var with a decimal literal gives a double, but var with an integer literal gives an int, which is why a loop counter written as var i = 0 is an int and not a long.
When should you use it?
Use it when the type is obvious from the right-hand side and repeating it adds nothing: var now = Instant.now(); says more with the name than with the type. Avoid it when the inferred type is not obvious — var result = process(data); hides the return type that the reader needs, and the explicit version documents the contract for free. A common middle ground is to use var for values whose type is long and mechanical, and to write the type out whenever it carries information.
What are the naming conventions?
- Variables, parameters, methods:
camelCase, starting lowercase. - Classes and interfaces:
PascalCase, starting uppercase. - Constants:
UPPER_SNAKE_CASE. - Booleans read as assertions:
isReady,hasChildren,shouldRetry.
One word to avoid: tmp, data and value are not names, they are admissions that you did not think about the thing. The name is the cheapest documentation you will ever write, and a variable that is renamed three times in its life is telling you the domain is not understood yet.
Where do declarations live?
A variable declared inside a method body is a local variable: it exists only while the method runs, and each call gets its own copy. A variable declared as a field belongs to every instance of the class, or to the class itself when it is static. Fields hold the state that makes an object meaningful, and they carry a lifecycle that the rest of the program can observe, so they are given stricter treatment than locals.
public class Counter {
private int total; // field: one per instance
private static int created; // static field: one for the class
public void add(int amount) {
int running = total + amount; // local: exists for this call only
total = running;
created++;
}
}
The difference matters for thread safety and for testing: a local variable is private to the method, while a field can be changed by any code holding a reference to the object. That is why the rule of thumb is to declare variables as late as possible, and prefer locals.
Quick reference
- Locals must be definitely assigned before use — the compiler checks.
finalmeans assign-once;staticmeans one shared copy.static finalinUPPER_SNAKE_CASEis the constant pattern.varinfers a fixed type from the initialiser; it is local-only and needs a value.var i = 0is anint, not along.- Boolean names should read as assertions.
Try it yourself: write a class with a static final currency constant, a final per-instance field set in the constructor, and one local variable declared with var. Then try to reassign the constant and the var, and read both compiler errors carefully — they explain two different rules.