что такое даймонд оператор java
В чем смысл оператора diamond в Java 7?
оператор diamond в java 7 позволяет использовать следующий код:
однако в Java 5/6, я могу просто написать:
мое понимание стирания типа заключается в том, что они точно такие же. (В любом случае generic удаляется во время выполнения).
зачем вообще возиться с бриллиантом? Какие новые функции / тип безопасности это позволяет? Если он не дает никаких новых функций, почему они упоминают его как функцию? Насколько я это понимаю? концепция ошибочна?
7 ответов
дженерики существуют для обеспечения защиты времени компиляции от неправильных действий. В приведенном выше примере использование типа raw означает, что вы не получаете эту защиту и получите ошибку во время выполнения. Вот почему вы не должны использовать сырые типы.
Я думаю, что главное понять, что сырые типы (без <> ) нельзя рассматривать так же, как и универсальные типы. Когда вы объявляете необработанный тип, вы не получаете ни одного из преимущества и проверка типа дженериков. Вы также должны иметь в виду, что дженерики являются частью общего назначения языка Java. они не просто применяются к конструкторам no-arg Collection s!
ваше понимание слегка искажено. Алмазный оператор-хорошая функция, так как вам не нужно повторяться. Имеет смысл определить тип один раз, когда вы объявляете тип, но просто не имеет смысла определять его снова с правой стороны. Сухой принцип.
теперь, чтобы объяснить все пух об определении типов. Вы правы, что тип удаляется во время выполнения, но как только вы хотите получить что-то из списка с определением типа, вы получаете его обратно как тип вы определили при объявлении списка, иначе он потеряет все конкретные функции и будет иметь только объекты, за исключением случаев, когда вы приведете извлеченный объект к исходному типу, который иногда может быть очень сложным и привести к ClassCastException.
С помощью List list = new LinkedList() получите предупреждения rawtype.
эта строка вызывает предупреждение [unchecked]:
Итак, вопрос трансформируется: почему предупреждение [unchecked] не подавляется автоматически только в случае создания новой коллекции?
Я думаю, это было бы гораздо более сложной задачей, чем добавление <> характеристика.
UPD: я также думаю, что был бы беспорядок, если бы законно использовать сырые типы «только для нескольких вещей».
теоретически оператор diamond позволяет писать более компактный (и читаемый) код, сохраняя повторяющиеся аргументы типа. На практике это просто два запутанных символа, которые больше ничего не дают. Почему?
IMHO, имея ясный и простой способ пометить источник как Java 7, было бы более полезно, чем изобретать такие странные вещи. В таком отмеченном коде необработанные типы могут быть запрещены без потери чего-либо.
кстати., Я не думаю, что это следует делать с помощью переключателя компиляции. Java-версия файла программы является атрибутом файла, без опции вообще. Используя что-то тривиальное, как
может прояснить (вы можете предпочесть что-то более сложное, включая одно или несколько причудливых ключевых слов). Это даже позволило бы без проблем компилировать источники, написанные для разных версий Java. Это позволило бы вводить новые ключевые слова (например, «модуль») или отбрасывать некоторые устаревшие функции (несколько непубличных не вложенных классов в одном файле или что-либо еще) без потери совместимости.
Итак, лучше написать код, который не генерирует дополнительных предупреждений, а diamond operator позволяет сделать это удобным способом без ненужного повторения.
все сказанное в других ответах допустимо, но варианты использования не являются полностью допустимыми IMHO. Если один проверяет гуавы и особенно связанные с коллекциями вещи, то же самое было сделано со статическими методами. Е. Г. списки.newArrayList () что позволяет писать
или со статическим импортом
Это было бы более полезно, если бы они пошли на то, чтобы сделать поведение оператора diamond по умолчанию, то есть тип выводится с левой стороны выражения или если тип левой стороны выводился с правой стороны. Последнее происходит в Scala.
пункт для оператора Диаманта просто уменьшить печатать кода объявляя родовые типы. Это не имеет никакого влияния на время выполнения вообще.
единственная разница, если вы укажете в Java 5 и 6,
— Это, что вы должны указать @SuppressWarnings(«unchecked») до list (в противном случае вы получите непроверенное предупреждение о приведении). Насколько я понимаю, алмазный оператор пытается облегчить разработку. Ему нечего делать на выполнения дженериков в все.
Дельфин, монета и бриллиантовый оператор.
Релиз Java 7 должен выйти 28 Июля.
В связи с этой знаменательно датой, я наконец-то решил посмотреть, что нас всех ждет. Поскольку в последнее время в основном занимаюсь Scala, то на новые языковые фичи в Java не обращал серьезного внимания (только на тусовках java-программистов, плюс поглядывал что пишут в разных блогах жависты).
Технических новшеств очень много. Среди них самое интересное место занимает так называемый «Проект Монета (Project Coin)».
Он содержит в себе небольшие (конечно с их точки зрения) изменения в языке:
— Strings in switch
— Binary integral literals and underscores in numeric literals
— Multi-catch and more precise rethrow
— Improved type inference for generic instance creation (diamond)
— try-with-resources statement
— Simplified varargs method invocation
В этом посте я наверно не смогу написать про все фичи, пока хотел обратить внимание на некоторые интересные на мой взгляд моменты.
Improved type inference for generic instance creation (diamond)
Это так называемый оператор diamond (бриллиант, алмаз). Думаю называется так, потому что чем-то похож на камень: <>.
В качестве примера часто приводят такой код:
// Java 7 List a = new ArrayList<>(); // до Java 7 List b= new ArrayList ();
Это конечно очень красиво, т.к. мы смогли уменьшить размер кода. Но возникает вопрос, чем это лучше, если раньше можно сделать еще проще? Вот так:
// в Java 7 List a = new ArrayList<>(); // до Java 7 List b = new ArrayList();
Понятно, что мы здесь используем сырой тип (raw types) и поэтому некоторым программистам по «морально-этическим» соображениям такой код не нравится.
Хотя один java-программист даже не поленился и сравнил полученный байт-код: jdk-7-diamond-operator.
Он показал на примере, что никакой разницы от использования бриллианта в компилируемом байт-коде нет, т.к. весь этот сахар при компиляции пропадает.
Мне кажется, что более реальная польза, может быть показана в следующем примере:
List a = new ArrayList<>(); // Такой прокатит, хотя и ошибочный, что плохо. List b = new ArrayList(a); // Такой уже отрубится компилятором, что хорошо. List c = new ArrayList<>(a);
Таким образом, наш бриллиантик автоматически выведет тип. Затем поймет, что у нас должен быть конструктор от списка чисел. Потом компилятор понимает, что нам вместо этого подают список строк и создаст ошибку компиляции.
try-with-resource
Появился новый интерфейс AutoCloseable. Причем не где-то там в io (как Closeable), а в самом java.lang!
Этот интерфейс был подсунут в иерархию над Closeable (Closeable extends AutoCloseable).
Таким образом, автоматически все потоки (_Stream) и читатели/писатели(Reader/Writer) становятся также AutoCloseable.
В AutoCloseable есть один метод void close() throws Exception.
Идея заключается в том, что если указать AutoCloseable переменные (в терминах Java 7 они называются ресурсы) в скобочках после try, то они всегда автоматически закроются при выходе из try блока.
В качестве примера как правило приводят обычно что-то вроде:
Почему оператор diamond используется для вывода типа в Java 7?
List list = new ArrayList(); приведет к предупреждению компилятора.
Однако следующий пример компилируется без какого-либо предупреждения: List list = new ArrayList<>();
Мне любопытно, зачем вообще нужно вводить алмазного оператора. Почему бы просто не сделать вывод типа в конструкторе, если аргумент типа отсутствует (как это уже сделано для статических методов в java и используется коллекционными библиотеками, такими как google guava)
EDIT : используя ответ millimoose в качестве отправной точки, я посмотрел, что такое стирание типа на самом деле, и это не просто удаление всей информации о типе. Компилятор на самом деле делает немного больше(скопировано из официального документа doc ):
6 ответов
Мне было интересно, каково наказание за производительность для вывода общего типа в Java 7. Отличается ли стоимость generics method type inference (т. е. это ) от стоимости generics assignment type inference (т. е. это )? Я полагаю, что стоимость ничтожно мала, так как вывод типов на дженерики.
class A <> class B extends A <> class Holder < T object; Holder(T object) < this.object = object; >> Существует класс Holder для хранения некоторого объекта, созданного с помощью дженериков. В main() при инициализации с помощью оператора diamond он не компилируется (Java 7) с производным.
После дальнейшего рассмотрения и комментария @millimoose, я вижу, что изменения в поведении будут локальными для инициализатора и будут обнаружены во время компиляции. Рассмотрим следующую программу:
Окончательный ответ должен был бы исходить от кого-то, кто разработал эту функцию, но я предполагаю, что это делается для того, чтобы отличить ее от использования необработанных типов, которые заставляют компилятор делать что-то совсем другое ради совместимости. Выражение с необработанным типом в нем обрабатывается немного иначе, чем выражение, включающее универсальные типы, пример можно найти в этом вопросе SO: Generic портит коллекцию, не связанную с
Полный синтаксис, требуемый компилятором java 5 и 6, является:
List list = new ArrayList ();
Это часть улучшения Java дженериков в Java 7.
Раньше тебе пришлось бы писать
Теперь вы можете писать
Рассмотрим этот код Java, который пытается создать экземпляр некоторых List s: List list1 = new ArrayList (); List list2 = new ArrayList<>(); List list3 = new ArrayList () < >; List list4 = new.
um using Java 7 (1.7.0_67) and Project language level is set to 7-Diamonds,ARM, multi-catch. Мой код выглядит следующим образом: строки, которые выбрасывают ошибки компиляции при построении с использованием maven. private Map > classMap = new.
Было неприемлемо, чтобы один и тот же код успешно выполнялся на Java SE 6 и Java SE 7, но давал разные результаты.
За свои деньги я бы опустил алмаз и дал предупреждение (рассматриваемое как ошибка), если бы другой код был бы получен алгоритмом вывода, выбранным в 7 (по сути, то же самое, что и для вывода общего типа метода из J2SE 5.0). Если вы написали такой код, вероятно, неочевидно, можно ли его компилировать или нет.
Если ваш проект построен на maven, добавьте нижеприведенное в pom.xml под тегом. Это прекрасно работает..
Похожие вопросы:
Я смотрел виртуальное событие Oracle OTN: Java SE и JavaFX 2.0 (28 февраля 2012 года), и, говоря о новом алмазном операторе (эта штука Map > myMap = new.
Я знаю, что функции времени выполнения Java 7 недоступны с Java 6, но поскольку новый байт-код не был добавлен, новый байт-код invokedynamic релевантен только для языков, отличных от Java, мне было.
Мне было интересно, каково наказание за производительность для вывода общего типа в Java 7. Отличается ли стоимость generics method type inference (т. е. это ) от стоимости generics assignment type.
class A <> class B extends A <> class Holder < T object; Holder(T object) < this.object = object; >> Существует класс Holder для хранения некоторого объекта, созданного с помощью.
Рассмотрим этот код Java, который пытается создать экземпляр некоторых List s: List list1 = new ArrayList (); List list2 = new ArrayList<>();.
um using Java 7 (1.7.0_67) and Project language level is set to 7-Diamonds,ARM, multi-catch. Мой код выглядит следующим образом: строки, которые выбрасывают ошибки компиляции при построении с.
При упаковке моего проекта с использованием maven в intellij idea он выдает следующую ошибку, также моя версия компилятора java установлена на 1.8: оператор diamond не поддерживается в исходном коде.
С Java 7 мы могли бы использовать алмазный оператор: List list = new ArrayList<>(); Теперь я вижу в некоторых недавних кодах людей, бросающих алмазного оператора.
В чем смысл алмазного оператора (<>) в Java 7?
Оператор diamond в Java 7 разрешает код, подобный следующему:
Однако в Java 5/6 я могу просто написать:
Я понимаю, что стирание типов это то же самое. (Универсальный в любом случае удаляется во время выполнения).
Зачем вообще беспокоиться о бриллианте? Какие новые функциональные возможности/безопасность типов это позволяет? Если это не дает никакой новой функциональности, почему они упоминают это как функцию? Мое понимание этой концепции неверно?
Обобщения существуют для обеспечения защиты во время компиляции от неправильных действий. В приведенном выше примере использование необработанного типа означает, что вы не получите эту защиту и получите ошибку во время выполнения. Вот почему вы не должны использовать необработанные типы.
Теперь объясним весь паз об определении типов. Вы правы в том, что тип удаляется во время выполнения, но как только вы захотите извлечь что-то из списка с определением типа, вы получите его обратно как тип, который вы определили при объявлении списка, иначе он потеряет все специфические функции и будет иметь только Возможности объекта, за исключением случаев, когда вы приводите извлеченный объект к его исходному типу, который иногда может быть очень сложным и привести к исключению ClassCastException.
Использование List list = new LinkedList() вы получите предупреждения rawtype.
Эта строка вызывает предупреждение [unchecked]:
Итак, вопрос трансформируется: почему предупреждение [unchecked] не подавляется автоматически только для случая, когда создается новая коллекция?
UPD: Я также думаю, что был бы беспорядок, если бы по закону использовались необработанные типы «только для нескольких вещей».
Теоретически, оператор diamond позволяет писать более компактный (и читаемый) код, сохраняя аргументы повторяющегося типа. На практике это только два запутанных символа, которые больше ничего не дают. Зачем?
ИМХО, наличие ясного и простого способа пометить источник как Java 7 было бы более полезным, чем придумывать такие странные вещи. В таком маркированном коде необработанные типы могут быть запрещены, не теряя ничего.
Кстати, я не думаю, что это должно быть сделано с помощью переключателя компиляции. Версия программного обеспечения Java является атрибутом файла, никакой опции вообще нет. Используя что-то тривиальное, как
может прояснить это (вы можете предпочесть что-то более сложное, включая одно или несколько необычных ключевых слов). Это даже позволило бы без проблем скомпилировать исходные тексты, написанные для разных версий Java. Это позволило бы вводить новые ключевые слова (например, «модуль») или отбрасывать некоторые устаревшие функции (несколько непубличных не вложенных классов в одном файле или что-либо еще) без потери какой-либо совместимости.
Итак, лучше написать код, который не генерирует лишних предупреждений, а оператор Diamond позволяет делать это удобным способом без лишних повторов.
Все сказанное в других ответах является действительным, но варианты использования не полностью действительны ИМХО. Если кто-то проверяет Guava и особенно вещи, связанные с коллекциями, то же самое было сделано со статическими методами. Например. Lists.newArrayList () который позволяет писать
или со статическим импортом
У Гуавы есть и другие очень мощные функции, подобные этой, и я на самом деле не могу придумать много вариантов использования <>.
Было бы более полезно, если бы они использовали поведение по умолчанию для оператора diamond, то есть тип определялся с левой стороны выражения или если тип левой стороны был выведен с правой стороны. Последнее то, что происходит в Scala.
Единственное отличие, если вы укажете в Java 5 и 6,
является то, что вы должны указать @SuppressWarnings(«unchecked») для list (в противном случае вы получите непроверенное предупреждение о приведении). Насколько я понимаю, оператор бриллиантов пытается облегчить разработку. Он не имеет ничего общего с исполнением обобщений во время выполнения.
JDK 7: The Diamond Operator
Project Coin provides numerous ‘small language enhancements’ as a subset of the new JDK 7 features.
Project Coin provides numerous «small language enhancements» as a subset of the new JDK 7 features. I recently blogged on Project Coin’s switching on Strings and in this post I write about the new Diamond Operator ( <> ).
The Diamond Operator reduces some of Java’s verbosity surrounding generics by having the compiler infer parameter types for constructors of generic classes. The original proposal for adding the Diamond Operator to the Java language was made in February 2009 and includes this simple example:
For example, consider the following assignment statement:
Map > anagrams = new HashMap >();
This is rather lengthy, so it can be replaced with this:
Map > anagrams = new HashMap<>();
The above example provided in Jeremy Manson’s proposal (which was one of the first in response to a call for Project Coin ideas) is simple, but adequately demonstrates how the Diamond Operator is applied in JDK 7. Manson’s proposal also provides significant into why this addition was desirable:
The requirement that type parameters be duplicated unnecessarily like
this encourages an unfortunate
overabundance of static factory methods, simply because type inference
works on method invocations.
In other words, the JDK 7 Project Coin addition of a Diamond Operator brings type inference to constructors that has been available with methods. With methods type inference is implicitly done when one leaves off the explicit parameter type specification. With instantiation, on the other hand, the diamond operator must be specified explicitly to «tell» the compiler to infer the type.
In his original proposal, Manson points out that syntax without a special diamond operator could not be used to implicitly infer types for instantiations because «for the purposes of backwards compatibility, new Map() indicates a raw type, and therefore cannot be used for type inference.» The Type Inference page of the Generics Lesson of the Learning the Java Language trail of the Java Tutorials includes a section called «Type Inference and Instantiation of Generic Classes» that has already been updated to reflect Java SE 7. This section also describes why the special operator must be specified to explicitly inform the compiler to use type inference on instantiation:
Note that to take advantage of automatic type inference during generic class instantiation, you must specify the diamond operator. In the following example, the compiler generates an unchecked conversion warning because the HashMap() constructor refers to the HashMap raw type, not the Map > type
In Item 24 («Eliminate Unchecked Warnings») of the Second Edition of Effective Java, Josh Bloch emphasizes in bold text, «Eliminate every unchecked warning that you can.» Bloch shows an example of the unchecked conversion warning that occurs when one compiles code that uses a raw type on the right side of a declaration. The next code listing shows code that will lead to this warning.
If Effective Java, Bloch points out that this particular unchecked warning is easy to address by explicitly providing the parameter type to the instantiation of the generic class. With JDK 7, this will be even easier! Instead of needing to add the explicit text with these type names, the types can be inferred in many cases and specification of the diamond operator tells the compiler to make this inference rather than using the raw type.
The next Java code listing provides simplistic examples of these concepts. There are methods that demonstrate instantiation of a raw Set, instantiation of a Set with explicit specification of its parameter type, and instantiation of a Set with parameter type inferred because of specification of the diamond operator ( <> ).
When the above code is compiled, only the «raw» case leads to a warning.
Because these methods were all in a single class, there is a single stream of output for the entire class. However, to make it easier to compare them, I have cut-and-paste the output into a format that aligns the javap output for each method against each other. Each column represents the javap output for one of the methods. I have changed the font color of the particular method to blue to make it stand out and label that column’s output.
Other than the names of the methods themselves, there is NO difference in the javap output. This is because Java generics type erasure means the differentiation based on type is not available at runtime. The Java Tutorial on Generics includes a page called Type Erasure that explains this:
The compiler removes all information about the actual type argument at compile time.
Type erasure exists so that new code may continue to interface with legacy code. Using a raw type for any other reason is considered bad programming practice and should be avoided whenever possible.
As the quote above reminds us, erasure means that to bytecode a raw type is no different than an explicitly typed parameter type, but also encourages developers to not use raw types except for integrating with legacy code.
Conclusion
The inclusion of the diamond operator ( <> ) in Java SE 7 means that code that instantiates generic classes can be less verbose. Coding languages in general, and Java in particular, are moving toward ideas such as convention over configuration, configuration by exception, and inferring things as often as possible rather than requiring explicit specification. Dynamically typed languages are well known for type inference, but even statically-typed Java can do more of this than it does and the diamond operator is an example of this.
Dustin Marx is a principal software engineer and architect at Raytheon Company. His previous published work for JavaWorld includes Java and Flex articles and «More JSP best practices» (July 2003) and «JSP Best Practices» (November 2001).