Вопрос-ответ

What is the point of the diamond operator (<>) in Java?

В чем смысл оператора diamond (<>) в Java?

Оператор diamond в java 7 допускает код, подобный следующему:

List<String> list = new LinkedList<>();

Однако в Java 5/6 я могу просто написать:

List<String> list = new LinkedList();

Я понимаю, что при удалении типов это одно и то же. (Generic все равно удаляется во время выполнения).

Зачем вообще беспокоиться о diamond? Какую новую функциональность / безопасность типов он позволяет? Если это не дает никакой новой функциональности, почему они упоминают это как функцию? Мое понимание этой концепции ошибочно?

Переведено автоматически
Ответ 1

Проблема с

List<String> list = new LinkedList();

заключается в том, что с левой стороны вы используете универсальный тип List<String>, тогда как с правой стороны вы используете необработанный тип LinkedList. Эффективно существовать необработанные типы в Java только для совместимости с pre-дженерики код и никогда не должны использоваться в новом коде, если
вы абсолютно не должны.

Итак, если бы Java изначально имела дженерики и не имела типов, таких как LinkedList, которые изначально были созданы до появления дженериков, вероятно, можно было бы сделать так, чтобы конструктор для универсального типа автоматически выводил параметры своего типа из левой части присваивания, если это возможно. Но этого не произошло, и он должен по-разному обрабатывать необработанные типы и универсальные типы для обратной совместимости. В результате им приходится создавать немного другой, но не менее удобный способ объявления нового экземпляра универсального объекта без необходимости повторять параметры его типа... оператор diamond .

Что касается вашего исходного примера List<String> list = new LinkedList(), компилятор генерирует предупреждение для этого назначения, потому что это необходимо. Учтите это:

List<String> strings = ... // some list that contains some strings

// Totally legal since you used the raw type and lost all type checking!
List<Integer> integers = new LinkedList(strings);

Общие сведения существуют для обеспечения защиты во время компиляции от неправильных действий. В приведенном выше примере использование типа raw означает, что вы не получаете эту защиту и получите ошибку во время выполнения. Вот почему вам не следует использовать необработанные типы.

// Not legal since the right side is actually generic!
List<Integer> integers = new LinkedList<>(strings);

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

Я думаю, главное, что нужно понять, это то, что необработанные типы (без <>) нельзя обрабатывать так же, как универсальные типы. Когда вы объявляете необработанный тип, вы не получаете никаких преимуществ и проверки типов, присущих generics. Вы также должны иметь в виду, что generics являются частью языка Java общего назначения... они применимы не только к конструкторам без аргументов Collections!

Ответ 2

Ваше понимание немного неточно. Оператор diamond - приятная функция, поскольку вам не нужно повторяться. Имеет смысл определить тип один раз, когда вы объявляете тип, но просто не имеет смысла определять его снова с правой стороны. Принцип DRY.

Теперь объясним всю путаницу с определением типов. Вы правы в том, что тип удаляется во время выполнения, но как только вы захотите извлечь что-либо из списка с определением типа, вы получите это обратно как тип, который вы определили при объявлении списка, иначе он потеряет все специфические функции и будет иметь только функции объекта, за исключением случаев, когда вы приводите извлеченный объект к его исходному типу, что иногда может быть очень сложным и приводить к исключению ClassCastException.

Использование List<String> list = new LinkedList() приведет к получению предупреждений rawtype.

Ответ 3

Эта строка вызывает предупреждение [непроверено]:

List<String> list = new LinkedList();

Итак, вопрос трансформируется: почему [непроверенное] предупреждение не подавляется автоматически только для случая создания новой коллекции?

Я думаю, это было бы гораздо более сложной задачей, чем добавление <> функции.

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

Ответ 4

Теоретически оператор diamond позволяет вам писать более компактный (и читаемый) код за счет сохранения повторяющихся аргументов типа. На практике это всего лишь два запутанных символа, которые больше ничего вам не дают. Почему?


  1. Ни один здравомыслящий программист не использует необработанные типы в новом коде. Таким образом, компилятор может просто предположить, что, не вводя аргументов типа, вы хотите, чтобы он их выводил.

  2. Оператор diamond не предоставляет информации о типе, он просто говорит компилятору: "все будет в порядке". Поэтому, опустив его, вы не навредите. В любом месте, где оператор diamond разрешен, он может быть "выведен" компилятором.

ИМХО, иметь четкий и простой способ пометить исходный код как Java 7 было бы полезнее, чем изобретать такие странные вещи. В помеченном таким образом коде необработанные типы могут быть запрещены без потери чего-либо.

Кстати., я не думаю, что это следует делать с помощью переключателя компиляции. Версия Java программного файла является атрибутом файла, вообще без опции. Используя что-то столь же тривиальное, как

package 7 com.example;

можно было бы пояснить (вы можете предпочесть что-то более сложное, включающее одно или несколько необычных ключевых слов). Это даже позволило бы без каких-либо проблем компилировать исходные тексты, написанные для разных версий Java, вместе. Это позволило бы ввести новые ключевые слова (например, "модуль") или удалить некоторые устаревшие функции (несколько непубличных не вложенных классов в одном файле или что-либо еще) без потери какой-либо совместимости.

java generics