Java 10 представила заметную функцию: вывод типа локальной переменной. Это позволяет нам объявлять локальные переменные без указания типа с помощью ключевого слова var, компилятор автоматически определяет его тип. Это уменьшает количество сложных шаблонных объявлений и делает код более чистым.

Пример (старый способ объявления):

BufferedInputStream bufferedInStream = new BufferedInputStream(new FileInputStream("data.txt"));
List<String> list = new ArrayList<>();
Map<String, Integer> map = new HashMap<>();

Использование переменной:

var bufferedInStream = new BufferedInputStream(new FileInputStream("data.txt"));
var list = new ArrayList<String>();
var map = new HashMap<String, Integer>();

Однако мы не можем объявлять переменные везде с ключевым словом var. Есть некоторые ограничения, которые приведены ниже.

1. Уровень класса

Когда мы говорим «локальный» вывод типа переменной, мы можем использовать его строго в локальном контексте метода. Мы не можем объявить переменную внутри класса (статического или экземпляра), используя ключевое слово var. Компилятор выдает ошибку компиляции при попытке объявить ее внутри класса.

class Example {
    int rollNumber;
    var name; // Compiler Error! - Cannot resolve symbol 'var'
}

2. Нулевое присвоение

Вы должны присвоить переменной ненулевое значение во время объявления, чтобы компилятор мог определить ее тип. Присвоение переменной нулевой ссылки затрудняет определение ее типа компилятором. Следовательно, присваивание null во время объявления не допускается.

public static void main(String[] args) {
    var name = null; // Compiler Error! - Cannot infer type: variable initializer is 'null'
}

Однако вы можете присвоить значение null после первой инициализации.

public static void main(String[] args) {
    var name = "hello";
    name = null; // Valid now!
}

3. Составная инициализация

Java позволяет нам инициализировать несколько переменных одного типа в одном операторе, разделенном запятой. int length = 10, breadth = 20, height = 30; Однако это не разрешено при использовании thevar.

public static void main(String[] args) {
    var length = 10, breadth = 20, height = 30; // Compiler Error! 'var' is not allowed in a compound declaration
}

4. Инициализация массива

Не допускается инициализация массива без указания его типа при инициализации.

public static void main(String[] args) {
    var a = { 1, 2, 3 }; // Compiler Error! Array initializer is not allowed here
    var[] b = { 1, 2, 3 }; // Compiler Error! Unexpected token.
    var[] c = new int[] { 1, 2, 3 }; // Compiler Error! Unexpected token.

    var d = new int[] { 1, 2, 3 }; // Valid!
}

5. Лямбда-аргумент

В Java 10 var было ограничено только локальными переменными. Java 11 расширила область действия thevar до аргументов Lambda.

Пример:

BiConsumer<String, String> example = (var s1, var s2) -> System.out.println(s1 + s2); // Valid!

Однако смешивать thevar с другими типами в аргументах Lambda запрещено.

BiConsumer<String, String> example = (var s1, String s2) -> System.out.println(s1 + s2); // Compiler error. Cannot mix 'var' and explicitly typed parameters in lambda expression

6. Переменная цикла

Цикл for позволяет нам инициализировать несколько переменных. Java 10 позволяет нам использовать циклы thevar on for. Однако составное объявление и здесь не допускается.

for (var i = 0; i < 10; i++) { // Valid! Single var declaration is allowed
    System.out.println(i);
}


for (var i = 0, j = 10 ; i < 10; i++, j--) { // Compiler error! 'var' is not allowed in a compound declaration
    System.out.println(i + j);
}

7. Поймать блок

Java позволяет нам объявлять несколько блоков catch, чтобы по-разному обрабатывать различные исключения. Мы должны указать тип исключения в блоке catch для обработки конкретного исключения. Следовательно, использование var в блоке catch затрудняет определение того, в какой блок catch должно быть передано исключение.

try {
    var input = new FileReader("hello.txt");
} catch (var e) { // Compiler Error. Not allowed in catch block
    System.out.println("Error occured");
}

Заключение

Вывод типа локальной переменной — это заметное улучшение, сделанное в Java 10. Оно уменьшает стандартное объявление. Его можно использовать только в локальном контексте метода. Недопустимо использовать его на уровне класса, и нельзя делать нулевое присваивание, составное объявление, объявление массива, смешанные лямбда-аргументы и составное объявление в блоке for-loop и catch.