1. The var keyword
When we first start writing Java code, we encounter a strict type system: every variable must be declared explicitly — you must specify its type. This is helpful for reliability, but sometimes the declarations become verbose and clutter the code. To make life easier, Java added a convenient tool — type inference (var).
var lets you write shorter, cleaner code without sacrificing type safety: you write the value, and the compiler infers the type for you.
Example
var age = 23; // the compiler infers the type of 23 and produces int age
var name = "Anna"; // the compiler infers the type of "Anna" and produces String name
var price = 99.99; // the compiler infers the type of 99.99 and produces double price
Why was var introduced?
- Readability: no need to write long types (like HashMap<String, List<Integer>>) by hand.
- Flexibility: makes it easier to change types later: fix the right-hand side — the var on the left will adapt.
- Modern style: virtually all modern Java projects use var where the type is clear from the initializer.
When you can (and should) use var
- When the variable’s type is unambiguous from the right-hand side.
- When the type is obvious (var price = 100; — clearly an int).
- When the type is too long or complex (for example, HashMap<Integer, List<Calendar>>).
Example with an array
var numbers = new int[] { 1, 2, 3, 4 };
Example with a method
var input = console.nextLine(); // input is a String (the method returns a String)
When you should NOT use var
If the type is not obvious from the right-hand side, the code can become less clear. If in a month you won’t understand what the type is, it’s better to be explicit.
var mystery = DoSomethingVeryComplicated(); // WHO ARE YOU, mystery???
It’s better to specify the type explicitly here:
String result = DoSomethingVeryComplicated();
Golden rule: use var only where it doesn’t hurt readability!
var — only for local variables
The var keyword works only for local variables — inside methods. You cannot use var for:
- method parameters;
- class fields;
- constants.
How var works “under the hood”
- The Java compiler substitutes the correct type during compilation.
- After compilation there is no var left.
- No performance loss: it’s only a convenience for the programmer.
var year = 2025; // at compile time becomes: int year = 2025;
Common mistakes when using var
Uninitialized variable:
var a; // ERROR: Nothing to infer the type from!
Ambiguous initialization:
var list = null; // ERROR: Type of null cannot be inferred!
Reusing a variable with different types:
var value = 5; // value is int
value = "Five"; // ERROR: value is already int!
Comparison: explicit types vs var
| Scenario | Explicit type | var |
|---|---|---|
| Type is unambiguous | |
|
| Method returns a complex type | |
|
| Array | |
|
2. The final keyword: declaring constants
A constant is a variable whose value cannot be changed after initialization. Constants make code reliable, clear, and protect you from accidental changes to important numbers and strings.
- The number pi (PI = 3.14159…)
- Maximum number of users (MAX_USERS = 1000)
- Company name (COMPANY_NAME = "CodeGym")
In Java, the final modifier is used to declare a constant. It tells the compiler: “after the first assignment — you can’t change it anymore!”
final Tip IMYA_KONSTANTY = znachenie;
Syntax
final int DAYS_IN_WEEK = 7;
final double PI = 3.1415926535;
final String GREETING = "Hello, Java!";
Key points:
- A variable with final must be initialized (immediately or in a constructor — if it’s a class field).
- Attempting to change its value will result in a compilation error.
Example: you cannot change a final variable
final int MAX_USERS = 100;
MAX_USERS = 200; // Error: cannot assign a new value to a final variable
Note: if you uncomment the assignment, the project will not build.
3. static final: class-level constants
In Java, we often need constants that don’t depend on a specific object — “shared” across the entire class. For this, we use the combination of static + final.
Why static final?
- static — the variable belongs to the class (one per class).
- final — the value cannot be changed.
Syntax
public static final double PI = 3.1415926535;
public static final int MAX_USERS = 1000;
public static final String COMPANY_NAME = "CodeGym";
Where to declare? Usually — at the beginning of the class (before methods).
Example of usage in a class
public class MathUtils
{
public static final double PI = 3.1415926535;
public static double circleLength(double radius)
{
return 2 * PI * radius;
}
}
Call:
double len = MathUtils.circleLength(5);
System.out.println(len); // 31.4159...
Note: access the constant via the class name: MathUtils.PI.
4. Difference between plain final and static final
final — the value of a field cannot be changed after initialization, but each object has its own value.
static final — a single constant for the entire class, independent of objects.
Example: the difference in practice
public class User
{
public final String name; // Each User has its own name (final)
public static final String COMPANY = "CodeGym"; // One company for all (static final)
public User(String name)
{
this.name = name;
}
}
User u1 = new User("Vasya");
User u2 = new User("Petya");
System.out.println(u1.name); // Vasya
System.out.println(u2.name); // Petya
System.out.println(User.COMPANY); // CodeGym
Conclusion: name is an individual immutable field; COMPANY is a shared constant.
Naming conventions for constants
It’s customary to name constants in UPPER_CASE_WITH_UNDERSCORES.
public static final int MAX_USERS = 1000;
public static final double GRAVITY = 9.81;
public static final String DEFAULT_GREETING = "Hello, world!";
Tip: if you see a name like this, don’t try to change its value in code: the compiler won’t allow it.
5. Practice: declaring and using constants
Example: a class with constants
public class CircleCalculator
{
public static final double PI = 3.1415926535;
public static double getLength(double radius)
{
return 2 * PI * radius;
}
public static double getArea(double radius)
{
return PI * radius * radius;
}
}
Usage:
public class Main
{
public static void main(String[] args)
{
double r = 5.0;
System.out.println("Circumference: " + CircleCalculator.getLength(r));
System.out.println("Circle area: " + CircleCalculator.getArea(r));
}
}
Result:
Circumference: 31.415926535
Circle area: 78.5398163375
Attempt to change a constant
CircleCalculator.PI = 3.14; // Compilation error: cannot assign a value to final variable PI
6. Features and nuances
Constants for objects
You can declare final for object references, but that doesn’t make the object immutable! It only prevents assigning a different reference to the variable.
final StringBuilder sb = new StringBuilder("Hello");
sb = new StringBuilder("World"); // Error: cannot assign a new object
sb.append(", Java!"); // Allowed — the object's state is changing
System.out.println(sb); // Hello, Java!
Conclusion: final protects the reference, not the object. For true immutability, use immutable classes (for example, String, List.of(), etc.).
Using constants vs “magic numbers”
Bad style:
double area = 3.1415 * r * r; // What is 3.1415? Why this exact number?
Good style:
double area = PI * r * r; // It's immediately clear that we're using pi
7. Typical mistakes when working with constants and var
Mistake No. 1: attempting to change the value of a final variable. If a variable is declared with final, reassigning it will result in a compilation error.
Mistake No. 2: attempting to declare a constant using var. For constants, always use an explicit type together with final or static final. var is only for local variables.
Mistake No. 3: incorrect constant naming. Constants should use UPPER_CASE_WITH_UNDERSCORES. A declaration like final int maxUsers = 100; hurts readability.
Mistake No. 4: forgetting about scope. A constant declared inside a method is visible only within it. To use it across the whole class, declare it at the class level as static final.
Mistake No. 5: assuming that final makes an object immutable. final fixes the reference, not the object’s state — these are different things.
GO TO FULL VERSION