Quel est l'intérêt de l'opérateur diamond en Java 7?

l'opérateur diamond en java 7 permet le code comme suit:

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

Cependant en Java 5/6, je peux simplement écrire:

List<String> list = new LinkedList();

ma compréhension de l'effacement de type est que ceux-ci sont exactement les mêmes. (Le générique est supprimé à l'exécution de toute façon).

Pourquoi s'embêter avec le diamant? Quelle nouvelle fonctionnalité / sécurité de type permet-elle? S'il ne produit pas de nouvelles fonctionnalités, pourquoi le mentionnent-ils? comme une fonctionnalité? Est ma compréhension de cette notion erronée?

411
demandé sur ROMANIA_engineer 2010-11-12 19:43:23

7 réponses

Le problème avec les

List<String> list = new LinkedList();

est que sur le côté gauche, vous utilisez le Générique type List<String> où sur le côté droit vous utilisez le raw type LinkedList . Les types bruts en Java n'existent effectivement que pour la compatibilité avec le code pré-générique et ne devraient jamais être utilisés dans le nouveau code à moins que vous devez absolument.

maintenant, si Java avait des génériques dès le début et n'avait pas de types , tels que LinkedList , qui ont été créés à l'origine avant qu'il n'ait des génériques, il aurait probablement pu le faire de sorte que le constructeur pour un type générique infère automatiquement ses paramètres de type du côté gauche de l'affectation si possible. Mais il ne l'a pas fait, et il doit traiter les types bruts et les types génériques différemment pour rétrocompatibilité. Cela les oblige à faire un légèrement différent , mais également pratique, façon de déclarer une nouvelle instance d'un objet générique, sans avoir à répéter ses paramètres de type... le diamant de l'opérateur.

en ce qui concerne votre exemple original de List<String> list = new LinkedList() , le compilateur génère un avertissement pour cette tâche parce qu'il le doit. Considérez ceci:

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);

génériques existent pour fournir une protection de compilation contre faire la mauvaise chose. Dans l'exemple ci-dessus, utiliser le type brut signifie que vous n'obtenez pas cette protection et que vous obtiendrez une erreur à l'exécution. C'est pourquoi vous ne devez pas utiliser les types bruts.

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

Le diamant de l'opérateur, cependant, permet à la droite de l'affectation doit être défini comme un vrai générique instance avec le même type de paramètres que pour le côté gauche... sans avoir à saisir ces paramètres. Il vous permet de garder la sécurité des génériques avec presque le même effort que l'utilisation du type brut.

je pense que la chose clé à comprendre est que raw types (sans <> ) ne peuvent pas être traités de la même manière que les types génériques. Lorsque vous déclarez un type brut, vous n'obtenez aucun des avantages et la vérification de type des génériques. Vous devez également garder à l'esprit que les génériques font partie du langage Java ... ils ne s'appliquent pas seulement aux constructeurs no-arg de Collection s!

457
répondu ColinD 2010-11-12 18:01:27

votre compréhension est légèrement erronée. L'opérateur diamond est une fonctionnalité agréable car vous n'avez pas à vous répéter. Il est logique de définir le type une fois lorsque vous déclarez le type, mais cela n'a pas de sens de le définir à nouveau du côté droit. Le principe DRY.

maintenant pour expliquer tous les fuzz sur la définition des types. Vous avez raison que le type est supprimé à l'exécution, mais une fois que vous voulez récupérer quelque chose d'une liste avec définition de type, vous le récupérez. comme le type que vous avez défini lors de la déclaration de la liste sinon il perdrait toutes les fonctionnalités spécifiques et n'aurait que les fonctionnalités de L'objet, sauf quand vous avez moulé l'objet récupéré dans son type original qui peut parfois être très délicat et entraîner une ClassCastException.

en utilisant List<String> list = new LinkedList() vous obtiendrez des avertissements de type raw.

33
répondu Octavian Damiean 2010-11-12 16:52:25

cette ligne provoque l'avertissement [non vérifié]:

List<String> list = new LinkedList();

ainsi, la question se transforme: pourquoi l'avertissement [non vérifié] n'est pas supprimé automatiquement que pour le cas où la nouvelle collection est créée?

je pense que ce serait une tâche beaucoup plus difficile que d'ajouter <> .

UPD : je pense aussi qu'il y aurait un gâchis s'il était légalement d'utiliser des types bruts "juste pour quelques chose.'

15
répondu Roman 2010-11-12 17:02:48

en théorie, l'opérateur diamond vous permet d'écrire un code plus compact (et lisible) en sauvegardant les arguments de type répétés. En pratique, c'est juste deux caractères déroutants qui ne te donnent plus rien. Pourquoi?

  1. aucun programmeur sain utilise les types bruts dans le nouveau code. Ainsi le compilateur pourrait simplement supposer qu'en écrivant aucun argument de type vous voulez qu'il les infère.
  2. l'opérateur diamond ne fournit aucune information de type, il dit juste le compilateur, "il va bien". Donc en l'omettant vous ne pouvez pas faire de mal. À tout endroit où l'exploitant de diamants est légal, il pourrait être "inféré" par le compilateur.

IMHO, avoir une façon claire et simple de marquer une source comme Java 7 serait plus utile que d'inventer de telles choses étranges. Dans le code ainsi marqué, les types bruts pouvaient être interdits sans perdre quoi que ce soit.

Btw., Je ne pense pas que cela devrait être fait en utilisant un commutateur de compilation. La version Java d'un programme le fichier est un attribut du fichier, pas d'option. En utilisant quelque chose d'aussi insignifiant que

package 7 com.example;

pourrait le rendre clair (vous pouvez préférer quelque chose de plus sophistiqué, y compris un ou plusieurs mots clés Fantaisie). Cela permettrait même de compiler des sources écrites pour différentes versions de Java sans aucun problème. Cela permettrait d'introduire de nouveaux mots-clés (par exemple" module") ou de supprimer certaines fonctionnalités obsolètes (plusieurs classes non publiques non imbriquées dans un seul fichier ou quelque autre).) sans perdre de compatibilité.

14
répondu maaartinus 2011-01-19 11:37:00

quand vous écrivez List<String> list = new LinkedList(); , le compilateur produit un avertissement" non vérifié". Vous pouvez l'ignorer, mais si vous avez l'habitude d'ignorer ces avertissements que vous pouvez manquer une alerte qui vous avertit à propos d'un type réel problème de sécurité.

donc, il est préférable d'écrire un code qui ne génère pas d'avertissements supplémentaires, et Diamond operator vous permet de le faire de manière pratique sans répétition inutile.

7
répondu axtavt 2010-11-12 16:53:57

tout dit dans les autres réponses sont valides, mais les cas d'utilisation ne sont pas tout à fait valides IMHO. Si on vérifie Goyave et surtout les collections liées stuff, la même chose a été faite avec des méthodes statiques. Par exemple: listes.newArrayList () qui vous permet d'écrire

List<String> names = Lists.newArrayList();

ou avec importation statique

import static com.google.common.collect.Lists.*;
...
List<String> names = newArrayList();
List<String> names = newArrayList("one", "two", "three");

la goyave a d'autres caractéristiques très puissantes comme celle-ci et je Je ne peux pas penser à beaucoup d'utilisations pour le <>.

il aurait été plus utile s'ils étaient allés pour rendre le comportement de l'opérateur diamond par défaut, c'est-à-dire, le type est inféré du côté gauche de l'expression ou si le type du côté gauche a été inféré du côté droit. C'est ce qui se passe à Scala.

4
répondu allprog 2012-01-04 11:29:32

le point pour Diamond operator est simplement de réduire la dactylographie du code lors de la déclaration des types génériques. Il n'a aucun effet sur l'exécution que ce soit.

la seule différence si vous spécifiez en Java 5 et 6,

List<String> list = new ArrayList();

signifie que vous devez spécifier @SuppressWarnings("unchecked") au list (sinon vous obtiendrez un avertissement de coulée non vérifié). Je crois comprendre que diamond operator essaie de faciliter le développement. Il n'avait rien à faire sur l'exécution des génériques.

3
répondu Buhake Sindi 2010-11-12 16:57:14