Mirando a través del Java Collections Framework, he notado que algunas de las interfaces tienen el comentario (optional operation)
. Estos métodos permiten implementar clases a través de un UnsupportedOperationException
si simplemente no quieren implementar ese método.
Un ejemplo de esto es el addAll
método en Set Interface
.
Ahora, como se indica en esta serie de preguntas, las interfaces son un contrato definitorio de lo que el uso puede esperar.
Las interfaces son importantes porque separan lo que hace una clase de cómo lo hace. El contrato que define lo que un cliente puede esperar deja al desarrollador libre de implementarlo de la forma que elija, siempre y cuando mantenga el contrato.
y
Una interfaz es una descripción de las acciones que puede hacer un objeto ... por ejemplo, cuando se activa un interruptor de luz, la luz se enciende, no importa cómo, solo eso. En la programación orientada a objetos, una interfaz es una descripción de todas las funciones que debe tener un objeto para ser una "X".
y
Creo que el enfoque basado en la interfaz es significativamente mejor. Luego puede burlarse de sus dependencias muy bien, y todo está básicamente menos estrechamente acoplado.
¿Cuál es el punto de una interfaz?
Interfaz + Extensión (mixin) vs Clase Base
Dado que el propósito de las interfaces es definir un contrato y hacer que sus dependencias se acoplen libremente, ¿no tiene algunos métodos arrojar una UnsupportedOperationException
especie de derrota del propósito? Significa que ya no se me puede pasar ay Set
solo usarlo addAll
. Más bien, tengo que saber qué implementación se Set
me aprobó, para poder saber si puedo usarla addAll
o no. Eso me parece bastante inútil.
Entonces, ¿de qué sirve UnsupportedOperationException
? ¿Solo está compensando el código heredado y necesitan limpiar sus interfaces? ¿O tiene un propósito más sensorial que me estoy perdiendo?
fuente
addAll
enHashSet
. Difiere a la implementación predeterminada en laAbstractCollection
que ciertamente no se lanzaUnsupportedOperationException
.src.zip
él, funciona muy bien. Es útil saber exactamente qué código se está ejecutando el JRE a veces y no diferir al JavaDoc, que puede ser un poco detallado.Respuestas:
Mira las siguientes interfaces:
Todas estas interfaces declaran métodos de mutación como opcionales. Esto documenta implícitamente el hecho de que la clase Colecciones puede devolver implementaciones de esas interfaces que son inmutables: es decir, se garantiza que esas operaciones de mutación opcionales fallarán. Sin embargo, según el contrato en JavaDoc, todas las implementaciones de esas interfaces deben permitir las operaciones de lectura. Esto incluye las implementaciones "normales" como
HashSet
yLinkedList
así como también los envoltorios inmutablesCollections
.Contraste con las interfaces de cola:
Estas interfaces no especifican ninguna operación opcional: una cola, por definición, está diseñada para ofrecer y sondear elementos de manera FIFO. Una cola inmutable es tan útil como un automóvil sin ruedas.
Una idea común que surge repetidamente es tener una jerarquía de herencia que tenga objetos mutables e inmutables. Sin embargo, todos estos tienen inconvenientes. La complejidad enturbia las aguas sin resolver realmente el problema.
Un hipotético
Set
podría tener las operaciones de lectura, y una subinterfazMutableSet
podría tener las operaciones de escritura. Liskov nos dice queMutableSet
luego se podría pasar a cualquier cosa que necesite aSet
. Al principio, esto suena bien, pero considere un método que espera que el conjunto subyacente no se modifique mientras se lee: sería posible que dos hilos usen el mismo conjunto y violen la invariante del conjunto que no cambia. Esto podría causar un problema, por ejemplo, si un método lee un elemento del conjunto dos veces y está allí la primera vez, pero no la segunda.Set
podría no tener implementaciones directas, sino tenerMutableSet
yImmutableSet
como subinterfaces que luego se usan para implementar clases. Esto tiene el mismo problema que el anterior: en algún punto de la jerarquía, una interfaz tiene invariantes en conflicto. Uno dice "este conjunto debe ser mutable" y el otro dice "este conjunto no puede cambiar".Podría haber dos jerarquías completamente separadas para estructuras de datos mutables e inmutables. Esto agrega una tonelada de complejidad adicional para lo que termina siendo muy poca ganancia. Esto también tiene la debilidad específica de los métodos que no se preocupan por la mutabilidad (por ejemplo, solo quiero iterar una lista) ahora deben admitir dos interfaces separadas. Dado que Java está estáticamente tipado, esto significa métodos adicionales para manejar ambas jerarquías de interfaz.
Podríamos tener una única interfaz y permitir que las implementaciones arrojen excepciones si un método no le es aplicable. Esta es la ruta que tomó Java, y tiene más sentido. El número de interfaces se mantiene al mínimo, y no hay invariantes de mutabilidad porque la interfaz documentada no garantiza la mutabilidad de ninguna manera . Si se requiere una invariabilidad de inmutabilidad, use los envoltorios en
Collections
. Si un método no necesita cambiar una colección, simplemente no lo cambie. El inconveniente es que un método no puede garantizar que una colección no cambie en otro subproceso si se le proporciona una colección desde el exterior, pero eso es una preocupación del método de llamada (o su método de llamada) de todos modos.Lectura relacionada: ¿Por qué Java 8 no incluye colecciones inmutables?
fuente
MutableCollection
?Básicamente es YAGNI. Todas las colecciones concretas en la biblioteca estándar son mutables, implementan o heredan las operaciones opcionales. A ellos no les importan las colecciones inmutables de uso general y tampoco a la gran mayoría de los desarrolladores de Java. No van a crear una jerarquía de interfaz completa solo para colecciones inmutables, luego no incluirán ninguna implementación.
Por otro lado, hay algunos valores de propósito especial o colecciones "virtuales" que podrían ser muy útiles como inmutables, como un conjunto vacío y nCopies . Además, hay colecciones inmutables de terceros (como las de Scala), que pueden querer llamar al código Java existente, por lo que dejaron abierta la posibilidad de colecciones inmutables de la manera menos disruptiva.
fuente