var и final
До сих пор тип переменной вы писали сами: int age = 30;. Но справа стоит 30, и компилятор сам видит, что это целое число. Зачем тогда повторять?
Представьте, что вы приносите на склад вещь и просите подобрать для неё коробку. Кладовщик смотрит на вещь, выбирает подходящую форму и подписывает коробку. Дальше форма не меняется: в коробку из-под книги аквариум уже не положишь. Так в Java работает слово var:
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. Давайте разберём три объявления:
- В
var count = 10;справа литералint, поэтому уcountтипint. - В
var price = 2.5;справа литералdouble, иpriceполучает типdouble. - В
var letter = 'J';справа литералchar, иletterполучает типchar.
Компилятор подставляет тип один раз, при компиляции. Строка var count = 10; значит ровно то же, что int count = 10;, только короче. Поэтому count = 20; работает: новое целое число ложится в коробку для целых чисел.
Тип не меняется
var не превращает переменную в коробку «для чего угодно». Тип выбран при объявлении и дальше остаётся прежним:
var count = 10;
count = 2.5; // ✗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 и у переменной, объявленной прямо в классе:
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;, компилятор ответит:
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 написали без значения:
var total; // ✗
total = 5;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.