В чем смысл оператора diamond в Java 7?
оператор diamond в java 7 позволяет использовать следующий код:
List<String> list = new LinkedList<>();
однако в Java 5/6, я могу просто написать:
List<String> list = new LinkedList();
мое понимание стирания типа заключается в том, что они точно такие же. (В любом случае generic удаляется во время выполнения).
зачем вообще возиться с бриллиантом? Какие новые функции / тип безопасности это позволяет? Если он не дает никаких новых функций, почему они упоминают его как функцию? Насколько я это понимаю? концепция ошибочна?
7 ответов
вопрос с
List<String> list = new LinkedList();
это с левой стороны, вы используете generic тип List<String>
где с правой стороны вы используете raw тип LinkedList
. Необработанные типы в Java фактически существуют только для совместимости с кодом pre-generics и никогда не должны использоваться в новом коде, если только
ты должна это сделать.
теперь, если Java имел дженерики с самого начала и не имел типов, таких как LinkedList
, которые были изначально созданный до того, как у него были дженерики, он, вероятно, мог бы сделать это так, чтобы конструктор для универсального типа автоматически выводил свои параметры типа из левой части назначения, если это возможно. Но это не так, и он должен относиться к необработанным типам и общим типам по-разному для обратной совместимости. Это оставляет им необходимость сделать немного разные, но одинаково удобный способ объявления нового экземпляра универсального объекта без необходимости повторять его тип параметры... алмазный оператор.
насколько ваш оригинальный пример 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);
оператор алмазной , однако позволяет определить правую сторону назначения как истинный универсальный экземпляр с теми же параметрами типа, что и левая сторона... без необходимости вводить эти параметры снова. Это позволяет сохранить безопасность дженериков с почти те же усилия, что и при использовании raw-типа.
Я думаю, что главное понять, что сырые типы (без <>
) нельзя рассматривать так же, как и универсальные типы. Когда вы объявляете необработанный тип, вы не получаете ни одного из преимущества и проверка типа дженериков. Вы также должны иметь в виду, что дженерики являются частью общего назначения языка Java... они не просто применяются к конструкторам no-arg Collection
s!
ваше понимание слегка искажено. Алмазный оператор-хорошая функция, так как вам не нужно повторяться. Имеет смысл определить тип один раз, когда вы объявляете тип, но просто не имеет смысла определять его снова с правой стороны. Сухой принцип.
теперь, чтобы объяснить все пух об определении типов. Вы правы, что тип удаляется во время выполнения, но как только вы хотите получить что-то из списка с определением типа, вы получаете его обратно как тип вы определили при объявлении списка, иначе он потеряет все конкретные функции и будет иметь только объекты, за исключением случаев, когда вы приведете извлеченный объект к исходному типу, который иногда может быть очень сложным и привести к ClassCastException.
С помощью List<String> list = new LinkedList()
получите предупреждения rawtype.
эта строка вызывает предупреждение [unchecked]:
List<String> list = new LinkedList();
Итак, вопрос трансформируется: почему предупреждение [unchecked] не подавляется автоматически только в случае создания новой коллекции?
Я думаю, это было бы гораздо более сложной задачей, чем добавление <>
характеристика.
UPD: я также думаю, что был бы беспорядок, если бы законно использовать сырые типы "только для нескольких вещей".
теоретически оператор diamond позволяет писать более компактный (и читаемый) код, сохраняя повторяющиеся аргументы типа. На практике это просто два запутанных символа, которые больше ничего не дают. Почему?
- ни один здравомыслящий программист не использует необработанные типы в новом коде. Таким образом, компилятор может просто предположить, что, не записывая аргументы типа, вы хотите, чтобы он их выводил.
- оператор diamond не предоставляет информации о типе, он просто говорит компилятору:"все будет хорошо". Поэтому, опуская это тебе не повредит. В любом месте, где алмазный оператор является законным, он может быть "выведен" компилятором.
IMHO, имея ясный и простой способ пометить источник как Java 7, было бы более полезно, чем изобретать такие странные вещи. В таком отмеченном коде необработанные типы могут быть запрещены без потери чего-либо.
кстати., Я не думаю, что это следует делать с помощью переключателя компиляции. Java-версия файла программы является атрибутом файла, без опции вообще. Используя что-то тривиальное, как
package 7 com.example;
может прояснить (вы можете предпочесть что-то более сложное, включая одно или несколько причудливых ключевых слов). Это даже позволило бы без проблем компилировать источники, написанные для разных версий Java. Это позволило бы вводить новые ключевые слова (например, "модуль") или отбрасывать некоторые устаревшие функции (несколько непубличных не вложенных классов в одном файле или что-либо еще) без потери совместимости.
когда вы пишите List<String> list = new LinkedList();
, компилятор выдает предупреждение" unchecked". Вы можете игнорировать его, но если вы игнорировали эти предупреждения, вы также можете пропустить предупреждение, которое уведомляет вас о реальной проблеме безопасности типа.
Итак, лучше написать код, который не генерирует дополнительных предупреждений, а diamond operator позволяет сделать это удобным способом без ненужного повторения.
все сказанное в других ответах допустимо, но варианты использования не являются полностью допустимыми IMHO. Если один проверяет гуавы и особенно связанные с коллекциями вещи, то же самое было сделано со статическими методами. Е. Г. списки.newArrayList () что позволяет писать
List<String> names = Lists.newArrayList();
или со статическим импортом
import static com.google.common.collect.Lists.*;
...
List<String> names = newArrayList();
List<String> names = newArrayList("one", "two", "three");
Guava имеет другие очень мощные функции, такие как это, и я на самом деле не могу придумать много применений для .
Это было бы более полезно, если бы они пошли на то, чтобы сделать поведение оператора diamond по умолчанию, то есть тип выводится с левой стороны выражения или если тип левой стороны выводился с правой стороны. Последнее происходит в Scala.
пункт для оператора Диаманта просто уменьшить печатать кода объявляя родовые типы. Это не имеет никакого влияния на время выполнения вообще.
единственная разница, если вы укажете в Java 5 и 6,
List<String> list = new ArrayList();
- Это, что вы должны указать @SuppressWarnings("unchecked")
до list
(в противном случае вы получите непроверенное предупреждение о приведении). Насколько я понимаю, алмазный оператор пытается облегчить разработку. Ему нечего делать на выполнения дженериков в все.