Definition
var– A reserved type name introduced in Java 10 that enables local variable type inference by inferring the static type from the initializer expression.- Compile-time sugar – The inferred type is baked into the bytecode and the variable is just as strongly typed as if the type were written by hand; there is no runtime cost or dynamic typing.
- Locals only – Allowed for local variables, for-loop indexes, and try-with-resources variables, but not for fields, method parameters, or return types.
- Initializer required –
var x;does not compile because there is nothing to infer from, andvar x = null;fails becausenullhas no definite type. - Not a keyword –
varis a reserved type name, so existing code usingvaras a variable or method name still compiles.
Imagine a teller at National Bank of India filling out a form. The old rule said she must write the full category name twice: "Savings Account Ledger Entry" in the left box, then "new Savings Account Ledger Entry" in the right box, even though the right box already makes the category obvious. var lets her write just "this entry equals a new Savings Account Ledger Entry," and the bank's system still records it under the exact same category. The category is fixed and strict; she simply did not have to write it twice. But she cannot write var on an empty box with nothing in it, because then the system would have no way to know the category.
Understanding the Concepts
What is var and how does it work?
var reduces the boilerplate of repeating a type that the right-hand side already states. The compiler infers the exact static type and bakes it into the bytecode. The variable is permanently that type.
package com.bank.service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class VarBasicsDemo {
public void demonstrateVar() {
// Infers ArrayList<Account>
var accounts = new ArrayList<Account>();
// Infers BigDecimal
var balance = new BigDecimal("50000.00");
// Infers HashMap<String, List<Transaction>>
var byAccount = new HashMap<String, List<Transaction>>();
// balance = "hello"; // COMPILE ERROR: balance is BigDecimal
}
}
How is var different from JavaScript's var or Python's dynamic variables?
var in Java is NOT dynamic typing. The type is fixed at compile time and can never change. The bytecode is byte-for-byte identical to writing the type explicitly.
package com.bank.service;
import java.math.BigDecimal;
public class VarIsNotDynamic {
public void staticTyping() {
var fee = new BigDecimal("250.00");
// fee is permanently BigDecimal
// fee = "hello"; // COMPILE ERROR
// fee = 42; // COMPILE ERROR
// Identical to:
BigDecimal fee2 = new BigDecimal("250.00");
// Same bytecode, same type
}
}
Where can you use var? (Allowed positions)
var works for local variables, for-loop indexes, and try-with-resources variables.
package com.bank.service;
import java.io.FileReader;
import java.io.BufferedReader;
import java.util.List;
public class VarAllowedPositions {
public void allowedUses() {
// Local variable
var accountId = "SAV2001";
// For-loop index
var accounts = List.of("SAV2001", "CUR3001");
for (var id : accounts) {
System.out.println(id);
}
// Traditional for-loop
for (var i = 0; i < 10; i++) {
System.out.println(i);
}
// Try-with-resources
try (var reader = new BufferedReader(
new FileReader("accounts.csv"))) {
var line = reader.readLine();
} catch (Exception e) {
e.printStackTrace();
}
}
}
What are the limitations of var?
var cannot be used for fields, method parameters, return types, or constructor parameters. It needs an initializer, cannot be initialized with null alone, cannot type a lambda or method reference without a target type, and does not work with the curly-brace array initializer.
package com.bank.service;
public class VarLimitations {
// COMPILE ERROR: var not allowed for fields
// private var balance = BigDecimal.ZERO;
// COMPILE ERROR: var not allowed for parameters
// public void transfer(var amount) { }
// COMPILE ERROR: var not allowed for return types
// public var getBalance() { return BigDecimal.ZERO; }
public void limitations() {
// COMPILE ERROR: no initializer
// var x;
// COMPILE ERROR: null has no type
// var x = null;
// COMPILE ERROR: lambda needs target type
// var f = x -> x + 1;
// COMPILE ERROR: array initializer shorthand
// var arr = {1, 2, 3};
// OK: explicit array creation
var arr = new int[]{1, 2, 3};
}
}
What is the diamond operator trap with var?
var list = new ArrayList<>(); infers ArrayList, almost never what you want. The diamond has nothing to infer from when var is on the left. Always supply the type argument.
package com.bank.service;
import java.util.ArrayList;
import java.math.BigDecimal;
public class VarDiamondTrap {
public void diamondTrap() {
// WRONG: infers ArrayList<Object>
var wrong = new ArrayList<>();
wrong.add("SAV2001");
wrong.add(42); // Compiles! Not what you want
// CORRECT: supply type argument
var correct = new ArrayList<BigDecimal>();
correct.add(new BigDecimal("50000.00"));
// correct.add("hello"); // COMPILE ERROR: good!
}
}
What about primitive type inference?
var with numeric literals infers the default type: 0 gives int, 0.05 gives double. If you need long or float, you must use the suffix or write the type explicitly.
package com.bank.service;
public class VarPrimitives {
public void primitiveInference() {
var count = 0; // int
var rate = 0.05; // double
var total = 0L; // long (suffix L)
var precise = 0.05f; // float (suffix f)
// Danger: accumulating paise across millions of transactions
var paiseTotal = 0; // int: overflows at 2.1 billion!
// Should be: long paiseTotal = 0L;
}
}
When should you use var vs an explicit type?
Use var when the type is obvious from the right-hand side. Avoid it when the type is the information the reader needs.
package com.bank.service;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
public class VarStyleGuide {
// GOOD: type is obvious from constructor
public void goodUses() {
var account = new SavingsAccount("SAV2001");
var balances = new HashMap<String, BigDecimal>();
var entries = List.of("Deposit", "Withdrawal");
}
// BAD: type is not obvious
public void badUses() {
// var result = reconcile(); // What type is result?
// var data = service.process(); // What does process return?
// BETTER: explicit type documents intent
// BigDecimal result = reconcile();
// ReconciliationReport data = service.process();
}
}
What about the most-specific-type inference?
var infers the most specific type, so var list = new ArrayList gives ArrayList, not List. If you need the interface type, write it explicitly.
// Infers ArrayList<String>, not List<String>
var list = new ArrayList<String>();
// list is ArrayList<String>
// If you want List<String>:
List<String> list2 = new ArrayList<>();
What should a senior engineer know?
var is not a keyword but a reserved type name, so existing code using var as a variable name still compiles. The readability trade-off is the senior point: var on a method result lets a later return-type change compile silently, while an explicit type acts as a documented contract that fails to compile when the type changes. A good team rule: let the reader understand the type by looking only at the single line.
Visual Overview
┌───────────────────────────────────────────────────┐
│ var Type Inference (Compile Time) │
├───────────────────────────────────────────────────┤
│ │
│ Source code: │
│ var balance = new BigDecimal("50000.00"); │
│ │
│ Compiler infers: │
│ BigDecimal balance = new BigDecimal("50000.00");│
│ │
│ Bytecode: │
│ IDENTICAL to explicit type declaration │
│ No runtime cost, no dynamic typing │
│ │
│ ┌─────────────┐ ┌───────────────────┐ │
│ │ Allowed │ │ Not Allowed │ │
│ ├─────────────┤ ├───────────────────┤ │
│ │ Local vars │ │ Fields │ │
│ │ For-loop idx│ │ Method params │ │
│ │ Try-with-res│ │ Return types │ │
│ │ │ │ var x; (no init) │ │
│ │ │ │ var x = null; │ │
│ │ │ │ var f = x -> x; │ │
│ └─────────────┘ └───────────────────┘ │
└───────────────────────────────────────────────────┘
Key Takeaway
The var keyword, added in Java 10, gives local variable type inference. When you write var followed by an initializer, the compiler infers the exact static type from the right-hand side and bakes that type into the bytecode. This is pure compile-time sugar and not dynamic typing. The variable is just as strongly typed as if the type were written by hand, the bytecode is identical, and there is no runtime cost.
The limitations are where interviewers test depth. var works only for local variables, for-loop indexes, and try-with-resources variables. It cannot be used for fields, method parameters, or return types. It always needs an initializer, so a bare var x does not compile, and it cannot be initialized with null alone because null has no definite type. It also cannot type a lambda or method reference by itself, and combining var with the diamond operator infers Object.
In banking code at National Bank of India, var genuinely cleaned up the settlement service where declarations like Map
The subtle senior point is that an explicit type acts as a tripwire: if someone changes a method's return type, code with var silently re-infers the new type and keeps compiling, while an explicit type fails to compile and warns about the contract change.
Remember one sentence: var is compile-time type inference for locals that produces identical bytecode, so use it when the initializer makes the type obvious and write the type explicitly when hiding it would hurt readability.
---