Métodos opcionales en la interfaz de Java

Según tengo entendido, si implementa una interfaz en java, los métodos especificados en esa interfaz deben ser utilizados por las subclases que implementan dicha interfaz.

Me he dado cuenta de que en algunas interfaces, como la interfaz de la Colección, hay métodos que se comentan como opcionales, pero ¿qué significa esto exactamente? Me lanzó un poco, ya que pensé que todos los métodos especificados en la interfaz serían necesarios.

 dcpomero13 may. 2012 16:49
¿A qué métodos te refieres? No puedo encontrarlo en el JavaDoc o el código fuente
 xyz25 jul. 2012 15:55

Respuestas a la pregunta(12)

Solución de preguntas

El lenguaje Java requiere que todos los métodos en una interfaz sean implementados por cada implementación de esa interfaz. Período.No hay excepciones para esta regla. Decir "las colecciones son una excepción" sugiere una comprensión muy borrosa de lo que realmente está sucediendo aquí.

Es importante darse cuenta de que hay una especie de dos niveles de conformidad con una interfaz:

Lo que el lenguaje Java puede comprobar. Esto prácticamente se reduce a: está ahíalgunos Implementación para cada uno de los métodos?

En realidad cumpliendo el contrato. Es decir, ¿la implementación hace lo que la documentación en la interfaz dice que debería?

Las interfaces bien escritas incluirán documentación que explica exactamente lo que se espera de las implementaciones. Tu compilador no puede comprobar esto por ti. Necesitas leer los documentos, y hacer lo que dicen. Si no hace lo que dice el contrato, tendrá una implementación de la interfaz en la medida en quecompilador se refiere, pero será una implementación defectuosa / inválida.

Al diseñar la API de colecciones, Joshua Bloch decidió que, en lugar de tener interfaces muy finas para distinguir entre diferentes variantes de colecciones (por ejemplo: legible, escribible, acceso aleatorio, etc.), solo tenía un conjunto muy aproximado de interfaces, principalmenteCollection, List, Set yMapy luego documente ciertas operaciones como "opcional". Esto fue para evitar la explosión combinatoria que resultaría de las interfaces de grano fino. Desde elPreguntas frecuentes sobre diseño de API de colecciones Java:

Para ilustrar el problema en detalle sangriento, suponga que desea agregar la noción de modificabilidad a la Jerarquía. Necesita cuatro nuevas interfaces: ModifiableCollection, ModifiableSet, ModifiableList y ModifiableMap. Lo que antes era una jerarquía simple ahora es una heterarquía desordenada. Además, necesita una nueva interfaz de iterador para usar con colecciones no modificables, que no contiene la operación de eliminación. Ahora, ¿puedes acabar con UnsupportedOperationException? Lamentablemente no.

Considerar matrices. Implementan la mayoría de las operaciones de la Lista, pero no eliminan ni agregan. Son listas de "tamaño fijo". Si desea capturar esta noción en la jerarquía, debe agregar dos nuevas interfaces: VariableSizeList y VariableSizeMap. No es necesario que agregue VariableSizeCollection y VariableSizeSet, porque serían idénticas a ModifiableCollection y ModifiableSet, pero puede elegir agregarlas de todos modos por motivos de coherencia. Además, necesita una nueva variedad de ListIterator que no admita las operaciones de agregar y eliminar, para acompañar a la Lista no modificable. Ahora tenemos hasta diez o doce interfaces, más dos nuevas interfaces Iterator, en lugar de nuestras cuatro originales. ¿Terminamos? No.

Considere los registros (como los registros de errores, registros de auditoría y diarios para objetos de datos recuperables). Son secuencias naturales de solo apéndice, que admiten todas las operaciones de la Lista excepto para eliminar y establecer (reemplazar). Requieren una nueva interfaz central y un nuevo iterador.

¿Y qué pasa con las colecciones inmutables, en oposición a las no modificables? (es decir, colecciones que no pueden ser cambiadas por el cliente Y nunca cambiarán por ninguna otra razón). Muchos argumentan que esta es la distinción más importante de todas, porque permite que múltiples subprocesos accedan a una colección simultáneamente sin la necesidad de sincronización. Agregar este soporte a la jerarquía de tipos requiere cuatro interfaces más.

Ahora tenemos alrededor de una veintena de interfaces y cinco iteradores, y es casi seguro que en la práctica aún surjan colecciones que no encajan limpiamente en ninguna de las interfaces. Por ejemplo, las vistas de colección devueltas por Map son colecciones naturales que solo se eliminan. Además, hay colecciones que rechazarán ciertos elementos en función de su valor, por lo que aún no hemos eliminado las excepciones de tiempo de ejecución.

Cuando todo fue dicho y hecho, sentimos que era un compromiso de ingeniería sólido eludir todo el problema al proporcionar un conjunto muy pequeño de interfaces centrales que pueden generar una excepción de tiempo de ejecución.

Cuando los métodos en la API de colecciones se documentan como "operaciones opcionales", no significa que pueda dejar la implementación del método fuera de la implementación, ni tampoco que pueda usar un cuerpo de método vacío (por una parte, muchos de ellos). ellos necesitan devolver un resultado). Más bien, significa que una opción de implementación válida (una que aún se ajusta al contrato) es lanzar unaUnsupportedOperationException.

Tenga en cuenta que porqueUnsupportedOperationException es unRuntimeException puedes lanzarlo desde cualquier implementación de método, en lo que concierne al compilador. Por ejemplo, podrías lanzarlo desde una implementación deCollection.size(). Sin embargo, tal implementación violaría el contrato ya que la documentación paraCollection.size() No dice que esto está permitido.

Aparte: el enfoque utilizado por la API de colecciones de Java es un tanto controvertido (probablemente menos ahora que cuando se introdujo por primera vez, sin embargo). En un mundo perfecto, las interfacesno tener operaciones opcionales, y en su lugar se utilizarían interfaces de grano fino. El problema es que Java no admite tipos estructurales ni tipos de intersección inferidos, por lo que intentar hacer las cosas de la "manera correcta" termina siendo extremadamente difícil de manejar en el caso de las colecciones.

 Andrew S09 oct. 2015 23:05
Gracias Laurence que lo aclara.
 Andrew S08 oct. 2015 20:01
¿Por qué cuando implemento la interfaz de iterador en mi clase el compilador no se queja de la ausencia del método remove (), pero se queja de los métodos next () y hasNext () que faltan?
 Laurence Gonsalves09 oct. 2015 22:38
@AndrewS porque en Java 8remove se le dio una implementación por defecto. Si no lo implementas, entonces tu clase obtiene la implementación predeterminada. Los otros dos métodos que mencionas no tienen implementaciones por defecto.
 DaBlick04 abr. 2014 18:09
"El lenguaje Java requiere que todos los métodos en una interfaz sean implementados por cada implementación de esa interfaz. Período. No hay excepciones a esta regla". Excepto ... cuando hay. :-) Las interfaces de Java 8 pueden especificar una implementación de método predeterminada, por lo tanto, en Java 8 ... NO es cierto que todos los métodos de una interfaz deben IMPLEMENTARSE POR cada implementación de la interfaz, al menos no en el sentido de que usted debe Codificar la implementación en la clase conrete.
 Laurence Gonsalves05 abr. 2014 03:10
@DaBlick Cuando dije "se implementa en todas las implementaciones", no quise decir que dicha implementación del método deba residir en el origen de la clase implementadora. Incluso antes de Java 8, uno puede heredar una implementación de un método de interfaz, incluso de una clase que no implementa dicha interfaz. por ejemplo: crearFoo eso no se implementaRunnable con metodo publicovoid run(). Ahora crea una claseBar eseextends Foo yimplements Runnable sin sobresalirrun. Todavía implementa el método, aunque indirectamente. Del mismo modo, una implementación de método por defecto sigue siendo una implementación.
 DaBlick05 abr. 2014 15:18
Disculpas No estaba tratando de ser pediátricamente crítico tanto como para llamar la atención sobre una característica de Java 8 que podría ser relevante para la publicación original. En Java 8, ahora tiene la opción de tener implementaciones que no están codificadas en NINGUNA superclase ni subclase. Esto (IMHO) abre un nuevo mundo de patrones de diseño, incluidos algunos que pueden ser apropiados en los casos en que la prohibición de la herencia múltiple podría haber presentado algunos desafíos. Creo que esto generará un nuevo conjunto de patrones de diseño altamente útiles.
 xyz25 jul. 2012 15:52
+1 paraThere are no exceptions to this rule. Preguntándose por qué esta respuesta no está marcada como aceptada. Otros son buenos pero has dado más que suficiente.

Bueno, este tema ha sido dirigido a ... sí ... pero piensa, falta una respuesta. Estoy hablando de los "métodos predeterminados" de las interfaces. Por ejemplo, imaginemos que tendrás una clase para cerrar algo (como un destructor o algo así). Digamos que debería tener 3 métodos. Llamémoslos "doFirst ()", "doLast ()" y "onClose ()".

Así que decimos que queremos que cualquier objeto de ese tipo al menos se dé cuenta de "onClose ()", pero los otros son opcionales.

Puede darse cuenta de eso, utilizando los "Métodos predeterminados" de las interfaces. Lo sé, esto anularía la mayor parte del tiempo la razón de una interfaz, pero si está diseñando un marco, esto puede ser útil.

Así que si quieres realizarlo de esta manera, se vería lo siguiente

<code>public interface Closer {
    default void doFirst() {
        System.out.print("first ... ");
    }
    void onClose();
    default void doLast() {
        System.out.println("and finally!");
    }
}
</code>

Lo que sucedería ahora, si, por ejemplo, lo implementaras en una clase llamada "Prueba", el compilador estaría perfectamente bien con lo siguiente:

<code>public class TestCloser implements Closer {
    @Override
    public void onClose() {
        System.out.print("closing ... ");
    }
}
</code>

con la salida:

<code>first ... closing ... and finally!
</code>

o

<code>public class TestCloser implements Closer {
    @Override
    public void onClose() {
        System.out.print("closing ... ");
    }

    @Override
    public void doLast() {
        System.out.println("done!");
    }
}
</code>

con la salida:

<code>first ... closing ... done!
</code>

Todas las combinaciones son posibles. Cualquier cosa con "predeterminado" puede implementarse, pero no debe, sin embargo, cualquier cosa sin debe implementarse.

Espero que no esté del todo mal que ahora respondo.

¡Que tengas un buen día a todos!

[edit1]: Tenga en cuenta: Esto solo funciona en Java 8.

 AndroidLover22 dic. 2016 18:46
Esto solo funciona en Java 8 ¿verdad? *
 Thorben Kuck22 dic. 2016 23:22
Sí, lo siento, olvidé mencionar esto ... Debería ser editado ahora.
 AndroidLover23 dic. 2016 09:50
gracias por la ayuda Thorben

Una interfaz en Java simplemente declara el contrato para implementar clases. Todos los métodos en esa interfazdebe implementarse, pero las clases de implementación son libres de dejarlas sin implementar, es decir, en blanco. Como un ejemplo artificial,

<code>interface Foo {
  void doSomething();
  void doSomethingElse();
}

class MyClass implements Foo {
  public void doSomething() {
     /* All of my code goes here */
  }

  public void doSomethingElse() {
    // I leave this unimplemented
  }
}
</code>

Ahora me quedadoSomethingElse() no implementado, dejándolo libre para que mis subclases lo implementen. Eso es opcional.

<code>class SubClass extends MyClass {
    @Override
    public void doSomethingElse() {
      // Here's my implementation. 
    }
}
</code>

Sin embargo, si estás hablando de interfaces de colección, como han dicho otros, son una excepción. Si ciertos métodos se dejan sin implementar y los llama, pueden lanzarUnsupportedOperationException excepciones

 Micro20 may. 2016 22:14
Podría besarte mi amigo.

Los métodos opcionales en la interfaz de la Colección significan que la implementación del método puede lanzar una excepción, pero debe implementarse de todos modos. Como se especificóen los documentos:

Algunas implementaciones de colecciones tienen restricciones sobre los elementos que pueden contener. Por ejemplo, algunas implementaciones prohíben los elementos nulos, y algunas tienen restricciones en los tipos de sus elementos. El intento de agregar un elemento inelegible lanza una excepción no verificada, generalmente NullPointerException o ClassCastException. Intentar consultar la presencia de un elemento inelegible puede generar una excepción, o simplemente puede devolver falso; Algunas implementaciones mostrarán el comportamiento anterior y algunas mostrarán el último. Más generalmente, intentar una operación en un elemento inelegible cuya finalización no daría lugar a la inserción de un elemento inelegible en la colección puede generar una excepción o puede tener éxito, a opción de la implementación. Dichas excepciones están marcadas como "opcionales" en la especificación de esta interfaz.

 user16639013 may. 2012 17:03
Esto no parece aplicarse amétodos opcionales, sino que, por ejemplo,add((T)null) Puede ser válido en un caso, perono otro. Es decir, esto habla de excepciones opcionales / comportamiento ypara discusiones ("restricciones en elementos" ... "elemento no elegible" ... "excepciones marcadas como opcionales") y no abordamétodos opcionales.
 emory13 may. 2012 17:02
Nunca entendí realmente lo que los javadocs entendían por opcional. Creo que querían decir lo que dijiste. Pero la mayoría de los métodos son opcionales según ese estándar:new Runnable ( ) { @ Override public void run ( ) { throw new UnsupportedOperationException ( ) ; } };

Para compilar una clase de implementación (no abstracta) para una interfaz, se deben implementar todos los métodos.

sin embargo, si pensamos en un método que su implementación es un simple lanzamiento de excepción como 'no implementado' (como algunos métodos en elCollection interfaz), entonces elCollection La interfaz es la excepción en este caso, no el caso normal.Generalmente, la clase de implementación debe (y lo hará) implementar todos los métodos.

El "opcional" en la colección significa que la clase implementadora no tiene que 'implementarla' (de acuerdo con la terminología anterior), y simplemente lanzaráNotSupportedException).

Un buen ejemplo-add() Método para colecciones inmutables: el concreto solo implementará un método que no hace más que lanzar.NotSupportedException

En el caso deCollection se hace para evitar árboles de herencia desordenados, que harán que los programadores sean miserables, pero paramás En este caso, este paradigma no se recomienda, y debe evitarse si es posible.

Actualizar:

A partir de java 8, unmétodo por defecto Fue presentado.

Esto significa que una interfaz puede definir un método, incluida su implementación.
Esto se agregó para permitir agregar funcionalidad a las interfaces, al tiempo que sigue siendo compatible con versiones anteriores de piezas de código que no necesitan la nueva funcionalidad.

Tenga en cuenta que el método sigue implementado por todas las clases que lo declaran, pero utilizando la definición de la interfaz.

 user20742114 may. 2012 02:19
"no tiene que implementarlo (probablemente creará un método que lanza ...)". Esees Implementando el método.
 djechlin10 mar. 2013 16:29
El "opcional" en la colección significa que la clase implementadora no tiene que implementarlo ". Esto es simplemente falso. Por" no tiene que implementar "usted quiere decir otra cosa.
 amit13 may. 2012 17:04
@pst: yocreer eso es lo que pensaron los diseñadores cuando lo implementaron en primer lugar, pero no tengo forma de saberlo con certeza. yopensar cualquier enfoque diferente solo crearía un desastre, pero nuevamente, podría estar equivocado. El punto que intentaba mostrar aquí es: este ejemplo es la excepción, no el habitual, y aunque a veces puede ser útil para el caso general, debe evitarse, si es posible.
 Alberto14 may. 2012 16:11
Como desafortunadamente esta ha sido la respuesta aceptada, sugeriría volver a escribirla. Los 'Generalmente, implementar la clase debería (y lo hará) implementar todos los métodos 'es engañoso, ya queEJP ya señalado
 user16639013 may. 2012 17:02
En lugar de "no desordenar", creo que es más de "así es como es".

la respuesta a esta pregunta sigue siendo válida, pero ahora tiene más matices.

Primero, estas declaraciones de la respuesta aceptada siguen siendo correctas:

las interfaces tienen la intención de especificar sus comportamientos implícitos en un contrato (una declaración de reglas para el comportamiento que las clases implementadoras deben obedecer para que se consideren válidas)existe una distinción entre el contrato (reglas) y la implementación (codificación programática de las reglas)Los métodos especificados en la interfaz SIEMPRE DEBEN implementarse (en algún momento)

Entonces, ¿cuál es el matiz que es nuevo en Java 8? Cuando se habla de"Métodos opcionales" cualquiera de los siguientes son ahora aptos:

1. Un método cuya implementación es contractual opcional.

La "tercera declaración" dice que los métodos de interfaz abstractos siempre deben implementarse y esto sigue siendo cierto en Java 8+. Sin embargo, como en el Java Collections Framework, es posible describir algunos métodos de interfaz abstractos como "opcionales" en el contrato.

En este caso, el autor que está implementando la interfaz puede elegir no implementar el método. Sin embargo, el compilador insistirá en una implementación, por lo que el autor usa este código para cualquier método opcional que no sea necesario en la clase de implementación en particular:

<code>public SomeReturnType optionalInterfaceMethodA(...) {
    throw new UnsupportedOperationException();
}
</code>

En Java 7 y versiones anteriores, este era realmente el único tipo de "método opcional" que existía, es decir, un método que, si no se implementaba, arrojaba una excepción UnsupportedOperationException. Este comportamiento está necesariamente especificado por el contrato de interfaz (por ejemplo, los métodos de interfaz opcionales del Java Collections Framework).

2. Un método por defecto cuya reimplementación es opcional.

Java 8 introdujo el concepto demétodos por defecto. Estos son métodos cuya implementación puede ser proporcionada por la propia definición de la interfaz. En general, solo es posible proporcionar métodos predeterminados cuando el cuerpo del método se puede escribir utilizando otros métodos de interfaz (es decir, los "primitivos"), y cuandothis puede significar "este objeto cuya clase ha implementado esta interfaz".

Un método predeterminado debe cumplir el contrato de la interfaz (al igual que cualquier otro método de implementación de la interfaz). Por lo tanto, la especificación de una implementación del método de interfaz en una clase de implementación es a discreción del autor (siempre que el comportamiento sea adecuado para su propósito).

En este nuevo entorno, el Java Collections Framework.podría ser reescrito como

<code>public interface List<E> {
    :
    :
    default public boolean add(E element) {
        throw new UnsupportedOperationException();
    }
    :
    :
}
</code>

De esta forma, el método "opcional".add() tiene el comportamiento predeterminado de lanzar una UnsupportedOperationException si la clase de implementación no proporciona un nuevo comportamiento propio, que es exactamente lo que usted querría que sucediera y que cumple con el contrato para la Lista. Si un autor está escribiendo una clase que no permite agregar nuevos elementos a una implementación de la Lista, la implementación deadd() es opcional porque el comportamiento predeterminado es exactamente lo que se necesita.

En este caso, la "tercera declaración" anterior sigue siendo válida, porque el método se ha implementado en la propia interfaz.

3. Un método que devuelve unOptional resultado

El nuevo tipo de método opcional final es simplemente un método que devuelve unOptional. losOptional clase proporciona una forma decididamente más orientada a objetos de tratar connull resultados

En un estilo de programación fluido, como el que se ve comúnmente al codificar con la nueva API de secuencias de Java, un resultado nulo en cualquier punto hace que el programa se bloquee con una excepción NullPointerException. losOptional la clase proporciona un mecanismo para devolver resultados nulos al código del cliente de una manera que permite el estilo fluido sin causar que el código del cliente se bloquee.

Aunque no responde la pregunta del OP, vale la pena señalar que a partir de Java 8 se agregan métodos predeterminados a las interfaces.de hecho es factible. losdefault la palabra clave colocada en la firma del método de una interfaz dará como resultado que una clase tenga la opción de anular el método, pero no lo requiera.

Tutorial de Colecciones Java de Oracle:

Para mantener la cantidad de interfaces de recopilación central manejables, la plataforma Java no proporciona interfaces separadas para cada variante de cada tipo de recopilación. (Tales variantes pueden incluir inmutable, de tamaño fijo y solo de anexión). En cambio, las operaciones de modificación, en cada interfaz, se designan como opcional: una implementación determinada puede optar por no admitir todas las operaciones. Si se invoca una operación no compatible, una colección arroja unaExcepcionalOperaciónExcepción. Las implementaciones son responsables de documentar cuáles de las operaciones opcionales que admiten. Todas las implementaciones de propósito general de la plataforma Java son compatibles con todas las operaciones opcionales.

(aparte de aquellos condefault implementaciones en Java 8+), pero la implementación no tiene que hacer nada funcionalmente útil. Específicamente,

Puede estar en blanco (un método vacío).Puede simplemente lanzar unUnsupportedOperationException (o similar)

Este último enfoque a menudo se toma en las clases de recolección: todos los métodos aún están implementados, pero algunos pueden lanzar una excepción si se los llama en tiempo de ejecución.

llamada, por lo que era necesario implementar métodos opcionales ya que no quería implementar todos los métodos para cada devolución de llamada.

Entonces, en lugar de usar una interfaz, usé una clase con implementación vacía como:

<code>public class MyCallBack{
    public void didResponseCameBack(String response){}
}
</code>

Y puedes establecer la variable miembro CallBack de esta manera,

<code>c.setCallBack(new MyCallBack() {
    public void didResponseCameBack(String response) {
        //your implementation here
    }
});
</code>

Entonces llámalo así.

<code>if(mMyCallBack != null) {
    mMyCallBack.didResponseCameBack(response);
}
</code>

De esta manera, no tendría que preocuparse por implementar todos los métodos por devolución de llamada, sino solo anular los que necesita.

De hecho, estoy inspirado en SurfaceView.Callback2. Creo que esta es la forma oficial.

<code>public class Foo {
    public interface Callback {
        public void requiredMethod1();
        public void requiredMethod2();
    }

    public interface CallbackExtended extends Callback {
        public void optionalMethod1();
        public void optionalMethod2();
    }

    private Callback mCallback;
}
</code>

Si su clase no necesita implementar métodos opcionales, simplemente "implementa Callback". Si su clase necesita implementar métodos opcionales, simplemente "implementa CallbackExtended".

Perdón por la mierda de inglés.

Si pasamos por el código deAbstractCollection.java en grepCode, que es una clase ancestral para todas las implementaciones de colección, nos ayudará a entender el significado de los métodos opcionales. Aquí está el código para el método add (e) en la clase AbstractCollection. el método add (e) es opcional de acuerdo concolección interfaz

<code>public boolean  add(E e) {

        throw new UnsupportedOperationException();
    } 
</code>

El método opcional significa que ya está implementado en clases de antecesor y arroja la excepción UnsupportedOperationException en la invocación. Si queremos que nuestra colección sea modificable, deberíamos anular laOpcional Métodos en la interfaz de colección.

Su respuesta a la pregunta