162 votes

Pourquoi Java Map n’étend-il pas la collection?

J'ai été surpris par le fait qu' Map<?,?> n'est pas un Collection<?>.

J'ai pensé qu'il ferait BEAUCOUP de sens si elle a été déclarée comme telle:

public interface Map<K,V> extends Collection<Map.Entry<K,V>>

Après tout, un Map<K,V> est une collection d' Map.Entry<K,V>, n'est-ce pas?

Donc, il y a une bonne raison pourquoi il n'est pas mis en œuvre en tant que telle?


Grâce à Cletus pour une réponse faisant autorité, mais je suis toujours demander pourquoi, si vous pouvez déjà voir un Map<K,V> comme Set<Map.Entries<K,V>> (via entrySet()), il ne se contente pas d'étendre cette interface à la place.

Si un Map est Collection, quels sont les éléments? La seule réponse raisonnable est "paires Clé-valeur"

Exactement, interface Map<K,V> extends Set<Map.Entry<K,V>> serait génial!

mais cela donne un très limitées (et non pas particulièrement utile) Map d'abstraction.

Mais si c'est le cas, alors pourquoi est - entrySet spécifié par l'interface? Elle doit être utile en quelque sorte (et je pense qu'il est facile d'argumenter en faveur de cette position!).

Vous ne pouvez pas demander à ce que la valeur d'une clé de cartes, et vous ne pouvez pas supprimer l'entrée pour une clé donnée, sans savoir quelle valeur il cartes de.

Je ne dis pas que c'est tout là est à lui d' Map! Il peut et doit garder toutes les autres méthodes (à l'exception de entrySet, ce qui est redondant maintenant)!

139voto

cletus Points 276888

De la Java des Collections de Conception d'API FAQ:

Pourquoi ne pas la Carte d'étendre la Collecte?

C'est par la conception. Nous avons le sentiment que mappages ne sont pas des collections et de la les collections ne sont pas des mappages. Ainsi, il peu de sens pour la Carte d'étendre l'interface de Collecte (ou vice versa).

Si une Carte est une Collection, ce sont les éléments? La seule réponse raisonnable est "paires Clé-valeur", mais ce fournit un très limitées (et non pas particulièrement utile) de la Carte de l'abstraction. Vous ne pouvez pas demander à ce que la valeur d'une clé cartes à, et vous ne pouvez pas supprimer l'entrée pour une clé donnée, sans savoir ce que valeur des cartes.

Collection pourrait être déployés pour étendre La carte, mais cela soulève la question: quelles sont les clés? Il n'y a pas vraiment réponse satisfaisante, et en forçant un conduit à un manque de naturel de l'interface.

Les cartes peuvent être considérées comme des Collections (de clés, les valeurs, ou les couples), et de ce fait se reflète dans les trois "Collection opérations de vues" sur les Cartes (jeu de clés, entrySet, et les valeurs). Alors qu'il est, dans principe, possible d'afficher une Liste de une Carte cartographie des indices à des éléments,des c'est le méchant de la propriété que la suppression d'un élément de la Liste change la Clé associée à chaque élément avant de l'élément supprimé. C'est pourquoi nous n'avons pas une vue de la carte opération sur les Listes.

Mise à jour: je pense que la citation répond à la plupart des questions. Il est important de souligner la partie sur une collection d'entrées n'étant pas particulièrement utile de l'abstraction. Par exemple:

Set<Map.Entry<String,String>>

permettrait:

set.add(entry("hello", "world"));
set.add(entry("hello", "world 2");

(en supposant un entry() méthode qui crée un Map.Entry exemple)

Maps nécessite des clés uniques, donc ce serait en violation de cette. Ou si vous imposez des clés uniques sur un Set des entrées, il n'est pas vraiment un Set dans le sens général. C'est un Set avec d'autres restrictions.

Sans doute on pourrait dire le equals()/hashCode() relation pour Map.Entry a été purement sur la clé, mais même qui a des problèmes. Plus important encore, est-il vraiment ajouter de la valeur? Vous pouvez trouver cette abstraction pauses vers le bas une fois que vous commencez à regarder le cas du coin.

Il est intéressant de noter que l' HashSet est effectivement mis en œuvre comme un HashMap, et non pas l'inverse. Ce n'est qu'un détail d'implémentation, mais est néanmoins intéressants.

La raison principale pour entrySet() d'exister est de simplifier la traversée de sorte que vous n'avez pas à parcourir les touches et puis faire une recherche de la clé. Ne le prenez pas comme une preuve prima facie que l' Map devrait être un Set des entrées (à mon humble avis).

12voto

Jerry Coffin Points 237758

Même si vous avez obtenu un certain nombre de réponses qui couvrent votre question assez directement, je pense qu'il pourrait être utile de prendre un peu de recul, et de regarder la question un peu plus générale. C'est, de ne pas regarder plus précisément à la façon dont la bibliothèque Java qui arrive à être écrite, et de regarder pourquoi il est écrit de cette façon.

Le problème ici est que l'héritage modèles uniquement à un type de communauté. Si vous choisissez les deux choses qui semblent tous deux de la collection "like", vous pouvez probablement prendre un 8 ou 10 choses qu'ils ont en commun. Si vous choisissez une autre paire de "collection" comme de choses, ils vont aussi 8 ou 10 choses en commun-mais ils ne seront pas les mêmes 8 ou 10 choses que la première paire.

Si vous regardez une douzaine de différents "semblable à la collection" les choses, pratiquement chacun d'entre eux sera probablement quelque chose comme 8 ou 10 caractéristiques en commun avec au moins un autre, mais si vous regardez ce qui est partagé entre tous les l'un d'eux, vous êtes de gauche avec pratiquement rien.

C'est une situation que l'héritage (en particulier de l'héritage simple) n'a tout simplement pas de modèle. Il n'y a pas de propre ligne de démarcation entre ceux qui sont vraiment des collections et lesquels ne le sont pas, mais si vous voulez définir une véritable classe de Collection, vous êtes coincé avec la sortie de certains d'entre eux. Si vous ne laissez que quelques-uns d'entre eux, votre Collection de classe ne seront en mesure de fournir assez éparse de l'interface. Si vous laissez plus de l'extérieur, vous serez en mesure de donner un plus riche de l'interface.

Certains ont également la possibilité de ce qui revient à dire: "ce type de collection prend en charge l'opération de X, mais vous n'êtes pas autorisé à l'utiliser, par dérivation d'une classe de base qui définit X, mais la tentative d'utilisation de la dérivée de la classe de X échoue (par exemple, en lançant une exception).

Qui laisse tout de même un problème: presque indépendamment de qui vous quitter et de vous mettre en, vous allez devoir tracer une ligne entre les classes, et quelles sont. N'importe où vous tracer cette ligne, vous allez être laissé avec un clair, assez artificielle, de la division entre des choses qui sont tout à fait similaires.

11voto

ewernli Points 23180

Je suppose que le pourquoi est subjective.

En C#, je pense que Dictionary s'étend ou, au moins, met en œuvre une collection:

public class Dictionary<TKey, TValue> : IDictionary<TKey, TValue>, 
    ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, 
    IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback

Dans Pharo Smalltak ainsi:

Collection subclass: #Set
Set subclass: #Dictionary

Mais il existe une asymétrie avec certaines méthodes. Par exemple, collect: prend de l'association (l'équivalent d'une entrée), alors do: prendre les valeurs. Ils fournissent une autre méthode keysAndValuesDo: pour itérer le dictionnaire en entrée. Add: prend une association, mais remove: a été "supprimé":

remove: anObject
self shouldNotImplement 

Il est donc définitivement faisable, mais conduit à certaines autres questions au sujet de la hiérarchie de classe.

Ce qui est mieux, c'est subjectif.

3voto

Mnementh Points 19831

La réponse de cletus est bonne, mais je veux ajouter une approche sémantique. Pour combiner les deux n'a aucun sens, pensez au cas où vous ajoutez une paire clé-valeur via l'interface de collection et que la clé existe déjà. L'interface Map n'autorise qu'une seule valeur associée à la clé. Mais si vous supprimez automatiquement l'entrée existante avec la même clé, la collection a ensuite ajouté la même taille qu'auparavant, ce qui est très inattendu pour une collection.

3voto

xagyg Points 4281

Java collections sont cassés. Il manque une interface, que de la Relation. Par conséquent, la Carte s'étend Relation s'étend Ensemble. Les Relations (aussi appelé multi-cartes) ont des paires nom-valeur. Cartes (aka "Fonctions"), ont des noms uniques (ou clés) qui, bien sûr, la carte des valeurs. Les séquences d'étendre Cartes (où chaque clé est un nombre entier > 0). Des sacs (ou multi-ensembles) de prolonger les Cartes (où chaque clé est un élément et chaque valeur est le nombre de fois que l'élément apparaît dans le sac).

Cette structure permettrait d'intersection, union etc. d'une gamme de "collections". Par conséquent, la hiérarchie doit être:

                                Set

                                 |

                              Relation

                                 |

                                Map

                                / \

                             Bag Sequence

Sun/Oracle/Java ppl - s'il vous plaît obtenir de droit la prochaine fois. Merci.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X