Какой смысл в бриллиантовом операторе (<>) в Java 7?

Алмазный оператор в java 7 позволяет использовать код следующим образом:

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

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

List<String> list = new LinkedList();

Мое понимание стирания стилей заключается в том, что они точно такие же. (Во всяком случае, общий доступ удаляется во время выполнения).

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

Ответы

Ответ 1

Проблема с

List<String> list = new LinkedList();

заключается в том, что с левой стороны используется общий тип List<String>, где с правой стороны используется необработанный тип 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);

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

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

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

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

Ответ 2

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

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

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

Ответ 3

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

List<String> list = new LinkedList();

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

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

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

Ответ 4

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

  • Ни один программист не использует правильные типы в новом коде. Таким образом, компилятор может просто предположить, что, не создавая аргументов типа, вы хотите, чтобы он их выводил.
  • Алмазный оператор не предоставляет информацию о типе, он просто говорит компилятор, "все будет хорошо". Поэтому, опуская его, вы не можете навредить. В любом месте, где алмазный оператор является законным, он может быть "выведен" компилятором.

IMHO, имея ясный и простой способ отметить источник как Java 7, будет более полезен, чем придумывать такие странные вещи. В так обозначенном коде необработанные типы могут быть запрещены, не теряя ничего.

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

package 7 com.example;

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

Ответ 5

Когда вы пишете List<String> list = new LinkedList();, компилятор выдает предупреждение "unchecked". Вы можете игнорировать это, но если вы игнорировали эти предупреждения, вы также можете пропустить предупреждение, которое уведомляет вас о проблеме безопасности в реальном типе.

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

Ответ 6

Все сказанные в других ответах действительны, но варианты использования не полностью действительны IMHO. Если вы проверите Guava и особенно связанные с коллекциями вещи, то это было сделано со статическими методами. Например. Lists.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 есть и другие очень мощные функции, подобные этому, и я действительно не могу придумать многого использования для < > .

Было бы более полезно, если бы они пошли на то, чтобы поведение оператора алмаза было по умолчанию, т.е. тип выводится с левой стороны выражения или если тип левой стороны был выведен с правой стороны. Последнее происходит в Scala.

Ответ 7

Точкой для оператора алмаза является просто сокращение ввода кода при объявлении общих типов. Это не влияет на время выполнения.

Единственное отличие, если вы указываете в Java 5 и 6,

List<String> list = new ArrayList();

заключается в том, что вы должны указать @SuppressWarnings("unchecked") в list (иначе вы получите предупреждение без предупреждения). Я понимаю, что алмазный оператор пытается упростить разработку. Это не имело ничего общего с выполнением дженериков во время выполнения.