Перейти к содержимому
Теория · Переменные и типы · урок 5 из 8

var и final

До сих пор тип переменной вы писали сами: int age = 30;. Но справа стоит 30, и компилятор сам видит, что это целое число. Зачем тогда повторять?

Представьте, что вы приносите на склад вещь и просите подобрать для неё коробку. Кладовщик смотрит на вещь, выбирает подходящую форму и подписывает коробку. Дальше форма не меняется: в коробку из-под книги аквариум уже не положишь. Так в Java работает слово var:

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: тип по значению

Слово var вместо типа просит компилятор определить тип по значению справа. Это называется выводом типа, и в Java он появился в версии 10. Давайте разберём три объявления:

  1. В var count = 10; справа литерал int, поэтому у count тип int.
  2. В var price = 2.5; справа литерал double, и price получает тип double.
  3. В var letter = 'J'; справа литерал char, и letter получает тип char.

Компилятор подставляет тип один раз, при компиляции. Строка var count = 10; значит ровно то же, что int count = 10;, только короче. Поэтому count = 20; работает: новое целое число ложится в коробку для целых чисел.

Тип не меняется

var не превращает переменную в коробку «для чего угодно». Тип выбран при объявлении и дальше остаётся прежним:

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

У count тип int, и дробное число в count не положить, как если бы вы написали int count = 10;. На собеседовании любят спрашивать, не стала ли Java с появлением var языком с динамической типизацией — таким, где тип переменной определяется уже во время работы программы и может меняться. Не стала: тип по-прежнему известен при компиляции, только его подставляет компилятор, а не вы.

Здесь картинка с кладовщиком неточна. Живой кладовщик мог бы взять коробку с запасом. Компилятор берёт ровно тип литерала: у var n = 10; тип int, даже если позже вы захотите положить туда число побольше.

Где работает var

  • Только у переменных, объявленных внутри метода, например внутри main.
  • Только когда значение задано сразу: компилятору нужно, из чего выводить тип.

final: запечатанная коробка

Слово final перед объявлением запрещает менять переменную, когда в ней уже есть значение. Это запечатанная коробка: что в неё положили, то и лежит. final бывает у переменной внутри main и у переменной, объявленной прямо в классе:

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 внутри main

final int limit = 90; — обычная переменная, которую больше нельзя изменить. Если ниже написать limit = 100;, компилятор ответит:

TEXT
error: cannot assign a value to final variable limit

Значение можно положить и позже, но только один раз: сначала final int limit;, затем limit = 90;. Имя такой переменной пишут как обычно: limit, maxPrice.

Константы

Значение, общее для всей программы, например предельную скорость, объявляют не внутри main, а прямо в классе, рядом с main. Такую переменную называют константой. Разберём строку static final int MAX_SPEED = 120;:

  • static — как у main: переменная принадлежит самому классу Main и существует в программе в одном экземпляре;
  • final запрещает её менять;
  • MAX_SPEED — имя константы: его пишут заглавными буквами, а слова разделяют подчёркиванием.

Изменить константу внутри main тоже не выйдет: программа не скомпилируется, как и с limit.

Частая ошибка

var написали без значения:

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

Компилятору не из чего выводить тип: у var total нет значения справа. Задайте значение сразу, var total = 5;, или напишите тип сами: int total;.

Главное

  • var выводит тип из значения справа один раз, при компиляции: var count = 10; — то же, что int count = 10;.
  • Тип переменной с var не меняется, поэтому count = 2.5; не скомпилируется.
  • final запрещает менять переменную после того, как в неё положили значение.
  • Константу объявляют в классе как static final и называют заглавными буквами: MAX_SPEED.