L'opérateur diamant dans java 7 autorise un code comme celui-ci:
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 ce sont exactement les mêmes. (Le générique est quand même supprimé au moment de l'exécution).
Pourquoi s'embêter avec le diamant? Quelle nouvelle fonctionnalité / sécurité de type permet-elle? Si cela ne donne aucune nouvelle fonctionnalité, pourquoi le mentionnent-ils comme une fonctionnalité? Ma compréhension de ce concept est-elle imparfaite?
java
generics
java-7
diamond-operator
tofarr
la source
la source
Réponses:
Le problème avec
est que sur le côté gauche, vous utilisez le type générique tandis
List<String>
que sur le côté droit vous utilisez le type brutLinkedList
. Les types bruts en Java n'existent effectivement que pour la compatibilité avec le code pré-générique et ne doivent jamais être utilisés dans du nouveau code, sauf si vous en avez absolument besoin.Maintenant, si Java avait des génériques depuis le début et n'avait pas de types, tels que
LinkedList
, qui ont été créés à l'origine avant d'avoir des génériques, il aurait probablement pu faire en sorte que le constructeur d'un type générique infère automatiquement ses paramètres de type à partir de la gauche - côté main de la mission si possible. Mais il ne l'a pas fait, et il doit traiter différemment les types bruts et les types génériques pour une compatibilité ascendante. Cela les oblige à créer une manière légèrement différente , mais tout aussi pratique, de déclarer une nouvelle instance d'un objet générique sans avoir à répéter ses paramètres de type ... l'opérateur diamant.En ce qui concerne votre exemple d'origine
List<String> list = new LinkedList()
, le compilateur génère un avertissement pour cette affectation car il le doit. Considère ceci:Les génériques existent pour fournir une protection au moment de la compilation contre les erreurs. Dans l'exemple ci-dessus, l'utilisation du type brut signifie que vous n'obtenez pas cette protection et obtiendrez une erreur au moment de l'exécution. C'est pourquoi vous ne devez pas utiliser de types bruts.
L'opérateur diamant, cependant, permet de définir le côté droit de l'affectation comme une véritable instance générique avec les mêmes paramètres de type que le côté gauche ... sans avoir à taper à nouveau ces paramètres. Il vous permet de conserver la sécurité des génériques avec presque le même effort que d'utiliser le type brut.
Je pense que la chose clé à comprendre est que les types bruts (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 sont une partie à usage général du langage Java ... ils ne s'appliquent pas seulement aux constructeurs sans argument deCollection
s!la source
-compatibility
commutateur de compilation alorsjavac
qu'en cas d'absence, il interdira tous les types bruts et appliquera uniquement les types strictement génériques? Cela rendra nos codes moins verbeux tels quels.List<String> strings = new List<>()
est OK, mais si vous définissezprivate List<String> my list;
, puis à mi-chemin de la page avec laquelle vous instanciezmy_list = new List<>()
, ce n'est pas cool! Que contient à nouveau ma liste? Oh, laissez-moi chercher la définition. Tout à coup, l'avantage du raccourci diamant disparaît.my_list = getTheList()
? Il existe plusieurs méthodes pour résoudre ce type de problèmes: 1. utilisez un IDE qui vous montre les types de variables lors du survol de la souris. 2. utilisez des noms de variables plus significatifs, tels queprivate List<String> strings
3. ne divisez pas la déclaration et l'initialisation des variables sauf si vous y êtes vraiment obligé.Votre compréhension est légèrement défectueuse. L'opérateur de diamant est une fonctionnalité intéressante 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 tout simplement pas de sens de le définir à nouveau sur le côté droit. Le principe DRY.
Maintenant, pour expliquer tout le fuzz sur la définition des types. Vous avez raison de dire que le type est supprimé lors de l'exécution, mais une fois que vous voulez récupérer quelque chose dans une liste avec la 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 le Fonctionnalités de l'objet, sauf lorsque vous convertissez l'objet récupéré en son type d'origine, ce qui peut parfois être très délicat et entraîner une exception ClassCastException.
L'utilisation
List<String> list = new LinkedList()
vous donnera des avertissements de type brut.la source
List<String> list = new LinkedList()
est le bon code. Vous le savez et je le sais aussi. Et la question (si je comprends bien) est: pourquoi seul le compilateur java ne comprend pas que ce code est assez sécurisé?List<String> list = new LinkedList()
n'est pas le bon code. Bien sûr, ce serait bien si c'était le cas! Et cela aurait probablement pu être le cas si Java avait des génériques depuis le début et n'avait pas à gérer la rétrocompatibilité des types génériques qui n'étaient pas génériques, mais c'est le cas.<?>
si vous vous connectez au code hérité) et l'opérateur diamant inutile ne doit pas exister.Cette ligne provoque l'avertissement [non coché]:
Ainsi, la question se transforme: pourquoi l'avertissement [non vérifié] n'est pas supprimé automatiquement uniquement pour le cas où une nouvelle collection est créée?
Je pense que ce serait une tâche beaucoup plus difficile que d'ajouter une
<>
fonctionnalité.UPD : Je pense aussi qu'il y aurait un gâchis s'il était légalement d'utiliser des types bruts «juste pour quelques petites choses».
la source
En théorie, l'opérateur Diamond vous permet d'écrire du code plus compact (et lisible) en enregistrant des arguments de type répétés. En pratique, ce ne sont que deux caractères confus qui ne vous donnent rien. Pourquoi?
À mon humble avis, avoir un moyen clair et simple de marquer une source comme Java 7 serait plus utile que d'inventer des choses aussi étranges. Dans un code aussi marqué, les types bruts pourraient être interdits sans rien perdre.
Btw., Je ne pense pas que cela devrait être fait en utilisant un commutateur de compilation. La version Java d'un fichier programme est un attribut du fichier, aucune option du tout. Utiliser quelque chose d'aussi trivial que
pourrait être clair (vous préférerez peut-être quelque chose de plus sophistiqué, y compris un ou plusieurs mots clés de 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 quoi que ce soit) sans perdre la compatibilité.
la source
new ArrayList(anotherList)
etnew ArrayList<>(anotherList)
(surtout si elle est attribuée àList<String>
etanotherList
est unList<Integer>
)?new @RawType List()
. C'est déjà une syntaxe Java 8 valide et les annotations de type permettent de l'utiliser à chaque endroit où cela est nécessaire, par exemple@RawType List = (@RawType List) genericMethod();
. Considérant que les types bruts créent actuellement un avertissement du compilateur à moins qu'un approprié@SuppressWarnings
n'ait été placé,@RawType
serait un remplacement raisonnable et une syntaxe plus subtile n'est pas nécessaire.Lorsque vous écrivez
List<String> list = new LinkedList();
, le compilateur génère un avertissement "non vérifié". Vous pouvez l'ignorer, mais si vous aviez l'habitude d'ignorer ces avertissements, vous risquez également de manquer un avertissement qui vous informe d'un problème de sécurité de type réel.Il est donc préférable d'écrire un code qui ne génère pas d'avertissements supplémentaires, et l'opérateur Diamond vous permet de le faire de manière pratique sans répétition inutile.
la source
Tout ce qui est dit dans les autres réponses est valable mais les cas d'utilisation ne sont pas complètement valides à mon humble avis. Si l'on vérifie Guava et surtout les trucs liés aux collections, la même chose a été faite avec des méthodes statiques. Par exemple Lists.newArrayList () qui vous permet d'écrire
ou avec importation statique
La goyave a d'autres fonctionnalités très puissantes comme celle-ci et je ne peux vraiment pas penser à beaucoup d'utilisations pour le <>.
Il aurait été plus utile de choisir le comportement par défaut de l'opérateur diamant, c'est-à-dire que le type est déduit du côté gauche de l'expression ou si le type du côté gauche était déduit du côté droit. C'est ce qui se passe à Scala.
la source
Le point pour l'opérateur diamant est simplement de réduire le typage du code lors de la déclaration des types génériques. Cela n'a aucun effet sur l'exécution.
La seule différence si vous spécifiez en Java 5 et 6,
est que vous devez spécifier
@SuppressWarnings("unchecked")
lelist
(sinon vous obtiendrez un avertissement de cast non contrôlé). Je crois comprendre que l'exploitant de diamants essaie de faciliter le développement. Cela n'a rien à voir avec l'exécution des génériques à l'exécution.la source