Код
Java
#База знаний

Ключевое слово var в Java: что, зачем и почему

Разбираемся, что за var такой и в каких ситуациях он может пригодиться.

robby mccullough / unsplash

Что случилось?

Начиная с версии 10, в Java появилось ключевое слово var. Новая фича — local variable type inference (выведение типа локальной переменной) — не даёт переменным дополнительных возможностей. Впрочем, и ограничений на них не накладывает. Просто разработчикам не нужно теперь писать лишний код при объявлении переменных, когда их тип очевиден из контекста.

В каких случаях тип переменной очевиден?

Если переменной сразу же присваивается значение, для которого компилятор может однозначно понять тип. Вот три типичных ситуации, когда удобно перейти от явного указания типа к var:

1. При создании нового экземпляра класса. Особенно если у этого класса длинное название.

var theLongestNameYouCanEverImagine = new TheLongestNameYouCanEverImagine();

В этом случае компилятор «догадывается», что у переменной theLongestNameYouCanEverImagine должен быть тип TheLongestNameYouCanEverImagine.

2. В заголовке цикла.

for (var i = 1; i < 10; i++){
	//здесь что-то интересное происходит
}

Здесь переменной i неявно устанавливается тип int.

Если инициализировать переменную целым числом, то по умолчанию для неё будет определён тип int. Чтобы компилятор решил иначе, нужны подсказки-постфиксы: L — для типа long, F — для float, D — для double, или явное приведение к другому типу.

var a = 2; // тип переменной a — int 
var b = 2L; // тип переменной b — long 
var c = 2F; // тип переменной c — float 
var d = 2D; // тип переменной d — double 
var e = (short) 2; //тип переменной e — short

3. В блоке try-with-resources.

void copyFile(File src, File dest) throws IOException {
   try (var reader = new BufferedReader(new FileReader(src));
      var writer = new BufferedWriter(new FileWriter(dest))) {
      String s;
      while ((s = reader.readLine()) != null) {
         writer.write(s);
         writer.newLine();
      }
   }
}

Тут в заголовке блока инициализируются две локальные переменные: у reader будет тип BufferedReader, у writer — BufferedWriter.

Присвоить значение сразу же означает, что нельзя сначала просто дать var-переменной имя и только следующим оператором инициализировать её:

var x; // не скомпилируется
x = 3; // не скомпилируется

А ещё важно не перепутать окончание оператора с концом строки. Операторы в Java не прерываются переносами строк, поэтому разрешается объявлять переменную в нескольких строках:

var x
      = 3; // отлично скомпилируется

Можно ли для любой переменной не указывать тип, если мы сразу её инициализируем?

Нет. На это намекает первая часть названия фичи — local variable. Ключевое слово var можно использовать только с локальными переменными, то есть переменными, которые объявлены:

  • внутри конструкторов;
  • внутри блоков инициализации;
  • внутри методов.

Например:

public class VarExample {

   public VarExample() { // var в конструкторе
       var constructorVar = "constructorVar";
   }

   { // var в блоке инициализации
       var initializerVar = "initializerVar";
   }

   void methodExample() { // var в методе
       var methodVar = "methodVar";
   }
}

Новый метод объявления неприменим к переменным экземпляра (instance variable) и переменным класса (статическим переменным). То есть вот такие строчки кода компилятор сочтёт ошибочными:

public class VarExample {

   var instanceVar = "instanceVar"; // не скомпилируется
   static var staticVar = "staticVar"; // не скомпилируется
}

Не путайте переменные, объявленные внутри методов, и переменные — параметры методов. С первыми var использовать можно, со вторыми — нельзя.

public int sum(var x, var y) { // не скомпилируется
  return x + y;
}

public int sum2and2() { // а так можно
   var x = 2;
   var y = 2;
   return x + y;
}

Можно ли инициализировать значением null?

И да, и нет. Сам по себе null не даёт компилятору никакой информации о типе — ведь такое значение может быть у любого ссылочного типа. Лучшее, что мог бы сделать компилятор в такой ситуации, — это посчитать, что новая переменная имеет тип Object. Но программистам-то обычно нужно что-то более конкретное, чем Object, — у этого типа не так уж много полезных свойств и методов, так что архитекторы Java решили, что лучше null при использовании с var просто запретить.

Поэтому строка ниже не скомпилируется:

var nullVar = null; // не скомпилируется

Но можно оставить подсказку компилятору:

var nullVar = (String) null;

И это объявление уже допустимо. Правда, не очень понятно, зачем так делать, — проще сразу явно указать тип.

А если с помощью var объявить сразу несколько переменных?

Нет, так не работает. Это просто нужно запомнить: var можно использовать только с одной новой переменной за раз. А вот так нельзя:

int a, var b = 3; // не скомпилируется
var a = 1, b = 2; // тоже не скомпилируется
var a = 1, var b = 2; // и даже так не скомпилируется
int a = 3, b = 2; // да-да, так всё ещё можно

Хочу изменить для var-переменной первоначально заданное значение. Это разрешено?

Да пожалуйста! При объявлении задаётся только начальное значение, и менять его никто не запрещает:

var s = "first value";
s = "second value";

Есть нюанс: ключевое слово var не отменяет правила для переменных с модификатором final. Значения final-переменных, даже введённых новомодным var, менять по-прежнему нельзя.

final var s = "first value";
s = "second value"; // не-не-не, вы же не просто так дописали модификатор final

И тип тоже можно менять?

А вот и нет. Сэкономить на названиях переменных и переиспользовать одну и ту же локальную переменную с разными типами данных не выйдет. Но самим помнить о том, у какой переменной какой тип, не придётся. У компилятора память всё равно лучше, так что он просто не позволит вам совершить такого рода ошибку:

var s = "string value"; // объявили переменную с неявным типом String
s = "another string value"; // присвоили другое строковое значение
s = 100; // не скомпилируется: попытка присвоить строковой 
         //переменной числовое значение

Не путайте Java с JavaScript: в языке JavaScript тоже есть ключевое слово var. И оно тоже используется для объявления переменных.

Только JavaScript не так строг к типам, как Java. Так что можно, например, присвоить переменной строковое значение, а через пару строчек кода — числовое.

В старом проекте есть переменная с именем var. Придётся ли её переименовывать, если я захочу перейти на десятую Java?

Не придётся, потому что var — это не зарезервированное слово. Оно может использоваться в качестве имени переменной или даже пакета. Вот так:

var var = "var"; // так можно

Правда, это не отменяет тот факт, что var — не лучшее имя для переменной. Оно не очень-то, а точнее, совсем не информативно.

Это ещё хорошо, что у вас в проекте никто не догадался так назвать класс, — вот его бы пришлось переименовывать с переходом к Java 10. Слово var нельзя использовать для именования нового типа — так не получится назвать класс, интерфейс или перечисление (enum).

Подытожим

  1. Ключевое слово var можно использовать при объявлении локальных переменных в конструкторах, блоках инициализации, методах.
  2. С ним не получится объявить параметры метода, переменные экземпляра или переменные класса.
  3. var нужно инициализировать сразу после именования — в одном операторе. При этом можно переносить такое объявление переменной на разные строки.
  4. Объявлять сразу несколько переменных с помощью var в одном операторе нельзя.
  5. Инициализировать var-переменную значением null без явного указания типа тоже нельзя.
  6. Значение var-переменной в дальнейшем меняться может, а вот тип — нет.
  7. var допустимо использовать в качестве названия переменной, но нельзя так именовать тип: класс, интерфейс или перечисление.

Чтобы ещё лучше разобраться с var, изучите это руководство. В нём собраны советы по использованию local variable type inference «из первых рук» — от сотрудника Oracle.

А если хотите больше узнать о языке Java в целом, приходите на наш курс «Профессия Java-разработчик». Вы научитесь программировать на самом востребованном языке, а мы поможем с трудоустройством.

Проверьте свой английский. Бесплатно ➞
Нескучные задания: small talk, поиск выдуманных слов — и не только. Подробный фидбэк от преподавателя + персональный план по повышению уровня.
Пройти тест
Понравилась статья?
Да

Пользуясь нашим сайтом, вы соглашаетесь с тем, что мы используем cookies 🍪

Ссылка скопирована