sort example collection colecciones java oop collections

example - ¿Por qué Java Map no extiende la colección?



java collection hierarchy (10)

Exactamente, el interface Map<K,V> extends Set<Map.Entry<K,V>> sería genial!

En realidad, si se implements Map<K,V>, Set<Map.Entry<K,V>> , entonces tiendo a estar de acuerdo .. Parece incluso natural. Pero eso no funciona muy bien, ¿verdad? Digamos que HashMap implements Map<K,V>, Set<Map.Entry<K,V> , LinkedHashMap implements Map<K,V>, Set<Map.Entry<K,V> etc ... eso es todo bueno, pero si tuviera entrySet() , nadie olvidará implementar ese método, y puede estar seguro de que puede obtener entrySet para cualquier Map, mientras que no lo está si espera que el implementador haya implementado ambas interfaces. .

La razón por la que no quiero tener la interface Map<K,V> extends Set<Map.Entry<K,V>> es simplemente, porque habrá más métodos. Y después de todo, son cosas diferentes, ¿verdad? También de manera muy práctica, si toco el map. en IDE, no quiero ver .remove(Object obj) y .remove(Map.Entry<K,V> entry) porque no puedo hacer hit ctrl+space, r, return y terminar con ello .

Me sorprendió el hecho de que Map<?,?> No sea una Collection<?> .

Pensé que tendría MUCHO sentido si se declarase así:

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

Después de todo, un Map<K,V> es una colección de Map.Entry<K,V> , ¿no es así?

Entonces, ¿hay una buena razón por la cual no se implementa como tal?

Gracias a Cletus por la respuesta más autorizada, pero todavía me pregunto por qué, si ya puedes ver un Map<K,V> como Set<Map.Entries<K,V>> (a través de entrySet() ), no lo hace simplemente extienda esa interfaz en su lugar.

Si un Map es una Collection , ¿cuáles son los elementos? La única respuesta razonable es "pares clave-valor"

Exactamente, el interface Map<K,V> extends Set<Map.Entry<K,V>> sería genial!

pero esto proporciona una abstracción de Map muy limitada (y no particularmente útil).

Pero si ese es el caso, ¿por qué se especifica entrySet en la interfaz? Debe ser útil de alguna manera (¡y creo que es fácil argumentar a favor de esa posición!).

No puede preguntar a qué valor se asigna una clave determinada, ni puede eliminar la entrada de una clave determinada sin saber a qué valor se asigna.

¡No digo que eso sea todo lo que tiene que hacer Map ! Puede y debe mantener todos los otros métodos (excepto entrySet , que ahora es redundante).


De las Preguntas frecuentes sobre diseño de la API de Java Collections :

¿Por qué Map no extiende la colección?

Esto fue por diseño. Creemos que las asignaciones no son colecciones y las colecciones no son asignaciones. Por lo tanto, tiene poco sentido que Map amplíe la interfaz de Colección (o viceversa).

Si un mapa es una colección, ¿cuáles son los elementos? La única respuesta razonable es "pares clave-valor", pero esto proporciona una abstracción de Mapa muy limitada (y no particularmente útil). No puede preguntar a qué valor se asigna una clave determinada, ni puede eliminar la entrada de una clave determinada sin saber a qué valor se asigna.

Se podría hacer una recopilación para extender Map, pero esto plantea la pregunta: ¿cuáles son las claves? No hay una respuesta realmente satisfactoria, y forzar una conduce a una interfaz antinatural.

Los mapas se pueden ver como colecciones (de claves, valores o pares), y este hecho se refleja en las tres "operaciones de vista de colección" en Maps (keySet, entrySet y values). Si bien, en principio, es posible ver una Lista como un mapa que mapea los índices a los elementos, esto tiene la desagradable propiedad de que al eliminar un elemento de la Lista se cambia la Clave asociada con cada elemento antes del elemento eliminado. Es por eso que no tenemos una operación de vista de mapa en Listas.

Actualización: creo que la cita responde la mayoría de las preguntas. Vale la pena destacar la parte sobre una colección de entradas que no es una abstracción particularmente útil. Por ejemplo:

Set<Map.Entry<String,String>>

permitiría:

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

(suponiendo que un método de entry() crea una instancia de Map.Entry )

Map requieren claves únicas, así que esto violaría esto. O si impone claves únicas en un Set de entradas, no es realmente un Set en el sentido general. Es un Set con más restricciones.

Podría decirse que podría decirse que la relación equals() / hashCode() para Map.Entry estaba puramente en la clave, pero incluso eso tiene problemas. Más importante aún, ¿realmente agrega algún valor? Puede encontrar que esta abstracción se rompe una vez que comienza a buscar en los casos de esquina.

Vale la pena señalar que el HashSet realidad se implementa como un HashMap , y no al revés. Esto es puramente un detalle de implementación, pero de todos modos es interesante.

La razón principal para que entrySet() exista es simplificar el recorrido, de modo que no tenga que atravesar las teclas y luego hacer una búsqueda de la tecla. No lo tome como una evidencia prima facie de que un Map debe ser un Set de entradas (imho).


La respuesta de cletus es buena, pero quiero agregar un enfoque semántico. Combinar ambos no tiene sentido, piense en el caso de que agregue un par de clave-valor a través de la interfaz de recopilación y que la clave ya exista. La interfaz de mapa permite solo un valor asociado con la clave. Pero si elimina automáticamente la entrada existente con la misma clave, la colección tiene después del agregado el mismo tamaño que antes, algo muy inesperado para una colección.


Las colecciones de Java están rotas. Falta una interfaz, la de Relación. Por lo tanto, Map extends Relation extends Set. Las relaciones (también llamadas multi-mapas) tienen pares únicos de nombre-valor. Los mapas (también conocidos como "Funciones") tienen nombres únicos (o claves) que, por supuesto, se asignan a los valores. Las secuencias extienden Mapas (donde cada clave es un entero> 0). Las bolsas (o conjuntos múltiples) extienden Mapas (donde cada clave es un elemento y cada valor es la cantidad de veces que aparece el elemento en la bolsa).

Esta estructura permitiría intersección, unión, etc. de un rango de "colecciones". Por lo tanto, la jerarquía debería ser:

Set | Relation | Map / / Bag Sequence

PPL de Sun / Oracle / Java - por favor hágalo bien la próxima vez. Gracias.


Recto y simple. La colección es una interfaz que espera solo un Objeto, mientras que Map requiere Dos.

Collection(Object o); Map<Object,Object>


Si bien obtuvo una cantidad de respuestas que cubren su pregunta de manera bastante directa, creo que podría ser útil retroceder un poco, y analizar la pregunta un poco más en general. Es decir, no para ver específicamente cómo se escribe la biblioteca de Java, y ver por qué está escrita de esa manera.

El problema aquí es que la herencia solo modela un tipo de comunidad. Si seleccionas dos cosas que parecen "similares a una colección", probablemente puedas elegir entre 8 o 10 cosas que tienen en común. Si seleccionas un par diferente de cosas "de colección", también tendrán 8 o 10 cosas en común, pero no serán las mismas 8 o 10 cosas que el primer par.

Si nos fijamos en una docena más o menos de cosas "similares a colecciones", prácticamente cada una de ellas probablemente tendrá algo así como 8 o 10 características en común con al menos otra, pero si nos fijamos en lo que se comparte en cada uno de ellos, te quedan prácticamente nada.

Esta es una situación en la que la herencia (especialmente la herencia individual) simplemente no se modela bien. No existe una línea divisoria clara entre cuáles de ellas son realmente colecciones y cuáles no, pero si quiere definir una clase de Colección significativa, tiene que dejar algunas de ellas. Si deja solo unos pocos, su clase Collection solo podrá proporcionar una interfaz bastante dispersa. Si deja más, podrá darle una interfaz más rica.

Algunos también toman la opción de decir básicamente: "este tipo de colección admite la operación X, pero no está permitido usarla, derivando de una clase base que define X, pero al intentar utilizar la clase derivada ''X falla (por ej. , lanzando una excepción).

Eso todavía deja un problema: casi sin importar cuál dejes afuera y cuál ingreses, vas a tener que trazar una línea dura entre las clases que están dentro y las que están fuera. No importa dónde dibujes esa línea, te quedarás con una división clara, más bien artificial, entre algunas cosas que son bastante similares.


Si observa la estructura de datos respectiva, puede adivinar fácilmente por qué Map no forma parte de Collection . Cada Collection almacena un único valor donde, como un Map almacena un par clave-valor. Entonces los métodos en la interfaz de Collection son incompatibles para la interfaz de Map . Por ejemplo, en Collection tenemos add(Object o) . ¿Cuál sería esa implementación en Map ? No tiene sentido tener dicho método en Map . En cambio, tenemos un método put(key,value) en Map .

El mismo argumento se removeAll() métodos addAll() , remove() y removeAll() . Por lo tanto, la razón principal es la diferencia en la forma en que se almacenan los datos en Map y Collection . Además, si recuerda Interfaz de Collection implementada Interfaz Iterable , es decir, cualquier interfaz con el método .iterator() debe devolver un iterador que debe permitirnos iterar sobre los valores almacenados en la Collection . Ahora, ¿qué devolvería dicho método para un Map ? ¿Un iterador clave o un iterador de valor? Esto tampoco tiene sentido.

Hay formas en que podemos iterar sobre las claves y valores almacenados en un Map y así es como es parte del marco de Collection .


Supongo que el porqué es subjetivo.

En C #, creo que Dictionary amplía o al menos implementa una colección:

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

En Pharo Smalltak también:

Collection subclass: #Set Set subclass: #Dictionary

Pero hay una asimetría con algunos métodos. Por ejemplo, collect: will toma asociación (el equivalente de una entrada), mientras que do: toma los valores. Proporcionan otro método keysAndValuesDo: para iterar el diccionario por entrada. Add: toma una asociación, pero remove: ha sido "suprimida":

remove: anObject self shouldNotImplement

Por lo tanto, es definitivamente factible, pero conduce a otros problemas relacionados con la jerarquía de clases.

Lo que es mejor es subjetivo.


Un mapa tiene tres colecciones diferentes: un conjunto de claves, un conjunto de entradas y un conjunto de pares clave-valor .
Puede obtener cualquiera de los tres con una sola llamada a un método.

Solo se podría decir razonablemente que el conjunto de pares clave-valor es "la colección", y es bastante antinatural.
Se podría decir que un Mapa es una Colección (de hecho, un Conjunto) de Map.Entry, pero es un poco incómodo y extraño.
Es aún menos apto para identificar el conjunto con su conjunto de valores o su conjunto de claves. Entonces, en lugar de ser confusos, hicieron que los tres fueran accesibles de manera fácil e igual.


Map<K,V> no debería extender Set<Map.Entry<K,V>> desde:

  • No puede agregar Map.Entry diferente con la misma clave al mismo Map , pero
  • Puede agregar diferentes Map.Entry s con la misma clave al mismo Set<Map.Entry> .