Алмазный оператор в Java 7 позволяет код, подобный следующему:
List<String> list = new LinkedList<>();
Однако в Java 5/6 я могу просто написать:
List<String> list = new LinkedList();
Я понимаю, что стирание типа это то же самое. (Универсальный в любом случае удаляется во время выполнения).
Зачем вообще беспокоиться о бриллианте? Какие новые функциональные возможности / безопасность типов это позволяет? Если это не дает никакой новой функциональности, почему они упоминают это как функцию? Мое понимание этой концепции неверно?
java
generics
java-7
diamond-operator
tofarr
источник
источник
Ответы:
Вопрос с
в том, что с левой стороны вы используете универсальный тип, а
List<String>
с правой стороны вы используете необработанный типLinkedList
. Необработанные типы в Java эффективно существуют только для совместимости с предварительным универсальным кодом и никогда не должны использоваться в новом коде, если только вам это не нужно.Теперь, если у Java были обобщения с самого начала и не было типов, таких как
LinkedList
, которые были изначально созданы до того, как у него были обобщения, это, вероятно, могло бы сделать это так, чтобы конструктор для обобщенного типа автоматически определял параметры своего типа слева - стороны задания, если это возможно. Но это не так, и он должен обрабатывать необработанные типы и универсальные типы по-разному для обратной совместимости. Это оставляет им необходимость сделать немного другой , но одинаково удобный способ объявления нового экземпляра универсального объекта без необходимости повторять его параметры типа ... оператор diamond.Насколько ваш оригинальный пример
List<String> list = new LinkedList()
, компилятор генерирует предупреждение для этого назначения, потому что он должен. Учти это:Обобщения существуют для обеспечения защиты во время компиляции от неправильных действий. В приведенном выше примере использование необработанного типа означает, что вы не получите эту защиту и получите ошибку во время выполнения. Вот почему вы не должны использовать необработанные типы.
Оператор diamond, однако, позволяет определять правую часть назначения как истинный универсальный экземпляр с такими же параметрами типа, как у левой стороны ... без необходимости повторного ввода этих параметров. Это позволяет сохранить безопасность дженериков практически с теми же усилиями, что и при использовании необработанного типа.
Я думаю, что ключевым моментом для понимания является то, что необработанные типы (без
<>
) нельзя рассматривать так же, как универсальные типы. Когда вы объявляете необработанный тип, вы не получаете ни одного из преимуществ и проверки типа обобщений. Вы также должны помнить, что дженерики являются частью общего назначения языка Java ... они не просто применяются к конструкторам без аргументовCollection
s!источник
-compatibility
переключение компилятора, тогда как если оно отсутствует, тоjavac
запретит все необработанные типы и будет применять только строго общие типы? Это сделает наши коды менее многословными.List<String> strings = new List<>()
Это нормально, но если вы определитеprivate List<String> my list;
, а затем на полпути вниз по странице, с которой вы создаете экземплярmy_list = new List<>()
, это не круто! Что мой список содержит снова? О, позвольте мне поискать определение. Внезапно, преимущество алмазного ярлыка прощается.my_list = getTheList()
? Есть несколько лучших способов решения таких проблем: 1. Используйте IDE, которая показывает типы переменных при наведении курсора мыши. 2. используйте более значимые имена переменных, такие какprivate List<String> strings
3. не разделяйте объявление и инициализацию переменных, если только вам это не нужно.Ваше понимание слегка ошибочно. Оператор с бриллиантами - хорошая функция, так как вам не нужно повторяться. Имеет смысл определять тип один раз, когда вы объявляете тип, но просто не имеет смысла определять его снова с правой стороны. СУХОЙ принцип.
Теперь объясним весь паз об определении типов. Вы правы в том, что тип удаляется во время выполнения, но как только вы захотите извлечь что-то из списка с определением типа, вы получите его обратно как тип, который вы определили при объявлении списка, иначе он потеряет все специфические функции и будет иметь только Возможности объекта, за исключением случаев, когда вы приводите извлеченный объект к его исходному типу, который иногда может быть очень сложным и привести к исключению ClassCastException.
Используя
List<String> list = new LinkedList()
вы получите необработанные предупреждения.источник
List<String> list = new LinkedList()
правильный код Вы знаете это, и я знаю это тоже. И вопрос (насколько я понимаю) таков: почему только Java-компилятор не понимает, что этот код достаточно безопасен?List<String> list = new LinkedList()
это не правильный код. Конечно, было бы хорошо, если бы это было! И это, вероятно, могло бы произойти, если бы в Java изначально были дженерики, и им не приходилось иметь дело с обратной совместимостью дженериков, которые раньше были неуниверсальными, но это так.<?>
если связаны с унаследованным кодом), а бесполезный оператор diamond не должен существовать.Эта строка вызывает предупреждение [unchecked]:
Итак, вопрос трансформируется: почему предупреждение [unchecked] не подавляется автоматически только для случая, когда создается новая коллекция?
Я думаю, это было бы гораздо более сложной задачей, чем добавление
<>
функции.UPD : Я также думаю, что был бы беспорядок, если бы юридически использовались необработанные типы «только для нескольких вещей».
источник
Теоретически, оператор diamond позволяет писать более компактный (и читаемый) код, сохраняя аргументы повторного типа. На практике это только два запутанных символа, которые больше ничего не дают. Почему?
ИМХО, наличие ясного и простого способа пометить источник как Java 7 было бы более полезным, чем придумывать такие странные вещи. В таком маркированном коде необработанные типы могут быть запрещены, не теряя ничего.
Кстати, я не думаю, что это должно быть сделано с помощью переключателя компиляции. Java-версия программного файла является атрибутом файла, никакой опции вообще нет. Используя что-то тривиальное, как
может прояснить это (вы можете предпочесть что-то более сложное, включая одно или несколько необычных ключевых слов). Это даже позволило бы без проблем скомпилировать исходники, написанные для разных версий Java. Это позволило бы вводить новые ключевые слова (например, «модуль») или отбрасывать некоторые устаревшие функции (несколько непубличных, не вложенных классов в одном файле или вообще) без потери какой-либо совместимости.
источник
new ArrayList(anotherList)
иnew ArrayList<>(anotherList)
(особенно, если она назначаетсяList<String>
иanotherList
являетсяList<Integer>
)?new @RawType List()
. Это уже допустимый синтаксис Java 8 и аннотации типов позволяют использовать его в любом месте, где это необходимо, например@RawType List = (@RawType List) genericMethod();
. Учитывая, что необработанные типы в настоящее время создают предупреждение компилятора, если@SuppressWarnings
не было помещено соответствующее,@RawType
было бы разумной заменой, и более тонкий синтаксис не требуется.Когда вы пишете
List<String> list = new LinkedList();
, компилятор выдает «непроверенное» предупреждение. Вы можете игнорировать это, но если вы раньше игнорировали эти предупреждения, вы также можете пропустить предупреждение, уведомляющее вас о реальной проблеме безопасности типа.Таким образом, лучше написать код, который не генерирует лишних предупреждений, а оператор Diamond позволяет делать это удобным способом без лишних повторов.
источник
Все сказанное в других ответах является действительным, но варианты использования не полностью действительны ИМХО. Если кто-то проверяет Guava и особенно вещи, связанные с коллекциями, то же самое было сделано со статическими методами. Например, Lists.newArrayList (), который позволяет писать
или со статическим импортом
У Гуавы есть и другие очень мощные функции, подобные этой, и я на самом деле не могу придумать много вариантов использования <>.
Было бы более полезно, если бы они использовали поведение по умолчанию для оператора diamond, то есть тип определялся с левой стороны выражения или если тип левой стороны был выведен с правой стороны. Последнее то, что происходит в Scala.
источник
Смысл для оператора diamond - просто уменьшить число типов кода при объявлении универсальных типов. Это никак не влияет на время выполнения.
Единственное отличие, если вы укажете в Java 5 и 6,
является то, что вы должны указать
@SuppressWarnings("unchecked")
дляlist
(в противном случае вы получите непроверенное предупреждение о приведении). Насколько я понимаю, оператор бриллиантов пытается облегчить разработку. Он не имеет ничего общего с исполнением обобщений во время выполнения.источник