Skip to content
Theory · Variables and types · lesson 5 of 8

var and final

So far you have written a variable's type yourself: int age = 30;. But 30 stands on the right, and the compiler can see on its own that it is a whole number. So why repeat it?

Picture bringing an item to a warehouse and asking for a box to fit it. The clerk looks at the item, picks a suitable shape and labels the box. After that the shape does not change: an aquarium will not go into a box made for a book. This is how the word var works in Java:

JAVA
public class Main {
    public static void main(String[] args) {
        var count = 10;
        var price = 2.5;
        var letter = 'J';
        count = 20;
        System.out.println(count);  // 20
        System.out.println(price);  // 2.5
        System.out.println(letter); // J
    }
}

var: the type from the value

The word var in place of a type asks the compiler to work out the type from the value on the right. This is called type inference, and Java got it in version 10. Let's walk through the three declarations:

  1. In var count = 10; the right side is an int literal, so count has the type int.
  2. In var price = 2.5; the right side is a double literal, and price gets the type double.
  3. In var letter = 'J'; the right side is a char literal, and letter gets the type char.

The compiler fills in the type once, at compile time. The line var count = 10; means exactly the same as int count = 10;, only shorter. That is why count = 20; works: a new whole number goes into a box for whole numbers.

The type does not change

var does not turn a variable into a box "for anything". The type is chosen at the declaration and stays the same afterwards:

JAVA
var count = 10;
count = 2.5; // ✗
TEXT
error: incompatible types: possible lossy conversion from double to int

count has the type int, and a fraction cannot go into it, as if you had written int count = 10;. Interviewers like to ask whether var makes Java a dynamically typed language, one where a variable's type is decided while the program runs and can change. It does not: the type is still known at compile time, only the compiler fills it in instead of you.

This is where the clerk picture falls short. A real clerk might pick a box with room to spare. The compiler takes exactly the literal's type: var n = 10; has the type int, even if later you want to put a bigger number there.

Where var works

  • Only for variables declared inside a method, such as main.
  • Only when the value is given right away: the compiler needs something to infer the type from.

final: a sealed box

The word final before a declaration forbids changing a variable once it holds a value. It is a sealed box: what was put in stays in. final appears on a variable inside main and on a variable declared right in the class:

JAVA
public class Main {
    static final int MAX_SPEED = 120;

    public static void main(String[] args) {
        final int limit = 90;
        System.out.println(limit);     // 90
        System.out.println(MAX_SPEED); // 120
    }
}

final inside main

final int limit = 90; is an ordinary variable that can no longer be changed. If you write limit = 100; below it, the compiler answers:

TEXT
error: cannot assign a value to final variable limit

The value can also be put in later, but only once: first final int limit;, then limit = 90;. Such a variable is named as usual: limit, maxPrice.

Constants

A value shared by the whole program, such as a speed limit, is declared not inside main but right in the class, next to it. Such a variable is called a constant. Let's take apart the line static final int MAX_SPEED = 120;:

  • static works as on main: the variable belongs to the class Main itself, and the program holds one copy of it;
  • final forbids changing it;
  • MAX_SPEED is the constant's name: it is written in capital letters, with words separated by underscores.

Changing the constant inside main fails too: the program does not compile, as with limit.

Common mistake

var was written without a value:

JAVA
var total; // ✗
total = 5;
TEXT
error: cannot infer type for local variable total

The compiler has nothing to infer the type from: var total has no value on the right. Give it a value right away, var total = 5;, or write the type yourself: int total;.

Key points

  • var infers the type from the value on the right once, at compile time: var count = 10; is the same as int count = 10;.
  • The type of a var variable does not change, so count = 2.5; does not compile.
  • final forbids changing a variable once it holds a value.
  • A constant is declared in the class as static final and named in capital letters: MAX_SPEED.