Java 10: Будет ли применение Java 7 Diamond работать с локальным типом вывода?

Из JEP 286 мы видим, что мы сможем использовать вывод локального типа (var) в JDK 10 (18.3), JEP утверждает, что следующие компиляции, которые ожидаются:

var list = new ArrayList<String>();  // infers ArrayList<String>

Мне интересно узнать, что произойдет, если мы попытаемся сделать следующее:

var list = new ArrayList<>();

Будет ли то, что я предложил во втором фрагменте, даже скомпилировать? Если это так (что я сомневаюсь), будет ли ArrayList принимать Object в качестве своего общего типа?

Я бы попробовал это сам, но у меня нет доступа к машинам, на которых я могу установить ранние выпуски.

Спасибо!

Ответ 1

Да, var и алмазный оператор можно объединить вместе. Компилятор выведет наиболее общий тип:

var list = new ArrayList<>(); // Infers ArrayList<Object>
var list = new ArrayList<>(List.of(1, 2, 3)); // Infers ArrayList<Integer>

И вы можете даже комбинировать их с анонимным классом:

var list = new ArrayList<>() {};

Ответ 2

"Работа с" - это неопределенный вопрос, поэтому вы, вероятно, получите смутные ответы.

Тип вывода - это не чтение ума; это просто ограничение решения. Чем меньше ограничений типа, тем вероятнее, что вы столкнулись с неудачей или неожиданным результатом (выведите тип, которого вы не ожидали, например Object).

Алмаз говорит: типы, которые мне нужны, вероятно, уже присутствуют с левой стороны, поэтому повторите их справа.

Локальный вывод типа переменной говорит: типы, которые мне нужны, вероятно, уже присутствуют с правой стороны, поэтому повторите их слева.

Общий вызов метода говорит: типы, которые мне нужны, вероятно, уже присутствуют в аргументах, поэтому повторяйте их как свидетелей.

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

List<String> anotherList = ...
var list = new ArrayList<>(anotherList);

Здесь компилятор может вывести параметр типа ArrayList, посмотрев тип аргумента на конструктор (тот, который принимает Collection<? extends E>). Таким образом, он передает T=String на RHS, а затем может вывести ArrayList<String> на LHS.

Другими словами, компилятор собирается делать то, что он может дать, предоставленную вами информацию. Чем меньше информации вы дадите, тем более вероятно, что он либо потерпит неудачу, либо не сделает то, что вы хотите.

Тем не менее, я думаю, вы задали неправильный вопрос. Вопрос о том, сколько вы можете уйти, не должен зависеть от того, "насколько компилятор позволит мне уйти", но "сколько урона я делаю для удобочитаемости моей программы". Чтение кода более важно, чем писать код. Оставляя все, что вы можете оставить, вряд ли будет максимально читаемо. Вам следует стараться уйти достаточно, чтобы убедиться, что читатель не смущен, когда сталкивается с вашей программой.

Ответ 3

Да, это скомпилировалось. Var в коде

var list = new ArrayList<>();

должен быть выведен как тип ArrayList<Object> (я считаю, что точно невозможно определить точный тип элемента из-за стирания), который будет таким же, как использование кода, например:

ArrayList list = new ArrayList<>(); 
// without the type of the element of list specified

где list в конечном итоге выводится как ArrayList<Object>.


Из FAQ в списке рассылки Брайана: -

Что произойдет, если мы попросим сделать вывод с обеих сторон?

Если вы скажете:

var x = new ArrayList<>() 

то вы просите компилятор вывести как аргумент типа List, так и тип x.

Но вы не предоставили достаточную информацию о типе для компилятора, чтобы сделать хорошую работу.

В большинстве случаев вы получите информативную ошибку компилятора, сообщающую вам, что вы просите, чтобы ваш ум читался. В некоторых случаях мы вернемся к выводу Object, как мы сейчас делаем:

Object o = new ArrayList<>()  // always inferred ArrayList<Object> here