2011-06-15 8 views
5

Let decir que tengo esta interfaz A que es implementada por múltiples proveedores:Java: ¿Cuál es la forma correcta de declarar un método de interfaz que puede arrojar una excepción?

interface A 
{ 
    void x(); 
    void y(); 
} 

Sin embargo, quiero proveedores sean capaces de lanzar excepciones para señalar que algo ha fallado y, potencialmente, el método podría lanzado una RuntimeException. En cada caso, el código que llama a estos métodos debe manejar el error y continuar. Solo porque un vendedor arroja un NPE, no quiero que el sistema se caiga. En lugar de dejar en manos de la persona que llama el método (o en realidad por el propio mantenimiento de línea), me gustaría para asegurarse de que cada llamada capturar todas las excepciones al declarar cada método como:

void x() throws Exception; 

pero esto es generalmente mal práctica (al PMD no le gusta y, en general, estoy de acuerdo con la regla de los métodos concretos), entonces me pregunto si esto es una excepción a la regla o si hay una forma mejor.

Déjenme ser claro, estoy buscando una solución donde la persona que llama de la interfaz se ve obligada a manejar todas las excepciones (incluyendo RuntimeException s).

Para detallar más mi entorno, todo esto se ejecuta dentro de un marco OSGi. Entonces, cada proveedor empaqueta su código en un paquete y OSGi manejará todas las excepciones para evitar que todo el sistema se cuelgue. Lo que realmente estoy buscando son las interfaces de servicio OSGi que serán llamadas por algunos paquetes centrales. Lo que quiero asegurar es que cuando repito todos los servicios, un servicio no lanza un NPE y detiene el proceso que se está ejecutando. Quiero manejarlo de forma más elegante detectando todas las excepciones lanzadas desde el servicio para que los otros servicios proporcionados sigan administrándose.

+0

Esta pregunta no es específica de las interfaces, ¿o sí? Quiero decir, los mismos problemas se aplican a los métodos abstractos e incluso a las implementaciones de métodos que podrían (o incluso podrían esperarse) anular. –

+0

Si este método está haciendo 'algo', ¿es algo tan amplio que podría arrojar alguna excepción? – blank

+0

Sería difícil restringir el conjunto de excepciones, entonces sí. –

Respuesta

7

Cree su propia clase de excepción, es decir. MySeviceException y tírelo desde la interfaz. La idea aquí es arrojar excepciones significativas, así que no tema crear muchas clases de excepciones personalizadas si eso proporciona la mayor legibilidad y facilidad de mantenimiento para sus propósitos. Puede ver las excepciones detalladas del proveedor en el proceso descendente y envolverlas como su excepción personalizada para que el flujo ascendente no tenga que ocuparse de las excepciones específicas del proveedor.

class MySeviceException extends Exception{ 
    public MySeviceException() {} 
    public MySeviceException(String msg) { super(msg); } 
    public MySeviceException(Throwable cause) { super(cause); } 
    public MySeviceException(String msg, Throwable cause) { super(msg, cause); } 
} 

interface A 
{ 
    void x() throws MySeviceExceptionException; 
    void y() throws MySeviceExceptionException; 
} 

Como regla general no coger Errors, siempre coger Exceptions y tratar con ella!

+0

Me gusta esta idea, pero no obliga a las personas que llaman a verificar RuntimeExceptions. Tal vez solo necesito que declare arrojar ambos. –

+3

@Dave H: no puede (y no debe intentar) obligar a las personas que llaman a buscar RuntimeExceptions, esa es la naturaleza de una excepción no verificada. – Robin

2

Los vendedores sin duda pueden lanzar RuntimeException al contenido de su corazón, porque están desmarcados. Eso significa que no tiene que agregar la cláusula throws a la interfaz.

También significa que los clientes no tendrán ninguna advertencia de la definición de la interfaz, y el compilador no aplicará un try/catch requerido. La única forma en que lo sabrán es leer tu Javadocss.

Puede crear una excepción personalizada que extienda java.lang.Exception; esa es una excepción marcada Tendrás que agregarlo a la cláusula throws; el compilador aplicará un try/catch alrededor de esos métodos; sus clientes tendrán que manejar el problema.

+0

Estoy buscando algo más ejecutable por el compilador en lugar de confiar en Javadocs. –

+0

Él está diciendo que no importa. Una vez más, pueden lanzar Excepciones de tiempo de ejecución cuando lo deseen y el compilador no forzará una prueba/captura. Incluso en la solución de CoolBeans, que es el mejor caso, no obliga al proveedor a cerrar su excepción en MyServiceException. Esta es una limitación de Java. Si permite que los proveedores creen módulos enchufables, debe negociar la comprensión de que su código no puede generar excepciones mortales en el marco y debe ser parte de su proceso de control de calidad para garantizar su cumplimiento. – nsfyn55

+0

Aparte de eso, todo lo que puede hacer es ajustar todas las llamadas de servicio en try {} catch (Exception e) – nsfyn55

1

Evitaría colocar la excepción en la interfaz debido a las limitaciones que usted impone a los implementadores. Si debo lanzar una excepción implementando su interfaz, hará las maquetas para las pruebas más difíciles.

Si algo falla en el código que implementa su interfaz, esa debería ser la preocupación del programador de la clase implementadora.

+0

El mero hecho de que la interfaz declare que se lanza una excepción no obliga a la implementación a lanzarla. Siempre puede arrojar menos. Además, el proveedor no siempre puede manejar si algo sale mal, puede ser necesario informarle a la persona que llama que algo está mal. –

1

La creación de una cláusula throws, incluso con un tipo de excepción personalizado, no es realmente una respuesta aquí. Siempre vas a tener cosas como NPE. Incluso si especifica a los proveedores que todas las excepciones deben estar envueltas en su tipo de excepción personalizado, habrá casos en los que alguien comete un error y se obtiene un NPE. Si no fuera por los errores, no tendrías NPEs.

Agregar "throws Exception" es una mala idea en muchos casos, pero en algunos casos funciona. En frameworks como Struts y JUnit puede agregar "throws Exception" (Excepción de tiradas) sin problemas porque el framework lo permite. (JUnit no sería muy útil si la primera excepción arrojó el paquete de prueba.)

Puede diseñar el sistema para que las llamadas al código del proveedor ocurran en módulos específicos que se conectan al sistema y que tienen excepciones. manejo manejado por el sistema, similar a cómo funcionan las acciones en Struts. Cada acción puede lanzar cualquier cosa, hay un controlador de excepción que registra lo que salió mal. De esta forma, la lógica comercial que llama a las API de los proveedores no debería verse afectada por la repetición inútil de las excepciones, pero si algo sale mal, el programa no se cierra.

+0

He editado la pregunta original. Estoy usando OSGi para que la aplicación realmente no salga, es más que la operación actual se interrumpe debido a 1 manzana mala. –

1

Estoy de acuerdo con PMD - declarar que arroja genérico Exception s es feo. Creo que es mejor

  • Definir nuevos, clases de excepción no en tiempo de ejecución específicos de dominio (si el built-in-one no lo harán, siempre se adhieren a clases predefinidas si coinciden con su semántica), y declarar en los métodos que pueden arrojarlos
  • Mantenga las excepciones de tiempo de ejecución al mínimo. Solo tienen sentido cuando no tienes control sobre cómo te llaman, y nada más servirá. Si tiene alguna razón para esperar que los arrojen en un código que está llamando, entonces tóquelos tan pronto como tengan sentido y vuelva a lanzarlos como excepciones estándar (consulte el punto anterior).

Las versiones recientes de Java le permiten encadenar excepciones. Por ejemplo, si usted consigue un NullPointerException ex al analizar un File f con una biblioteca externa, que se quiere cogerlo y volver a lanzar como, por ejemplo, un new FileParsingException("error parsing " + f + ": " + ex.getMessage(), ex);

+0

lo siento, pero esto es terrible, aumentas la cantidad de excepciones y finalmente esa excepción personalizada no te dice nada sobre lo que realmente salió mal, entonces tienes que hacer excavaciones arqueológicas en excepciones internas y cosas para encontrar la causa real. Excepción te dirá inmediatamente qué salió mal ... – Enerccio

+0

Estoy totalmente en desacuerdo. El envolver excepciones * es * la forma recomendada de manejar este caso (como lo defiende la respuesta aceptada, que está mejor escrita pero por lo demás muy similar a esta respuesta); porque el ajuste agrega el contexto que de otro modo no estaría disponible. En el ejemplo de esta respuesta, ¿cómo podría una NPE desenvuelta ayudar a diagnosticar un archivo mal formado que rompe el analizador? – tucuxi

1

Dependiendo de la configuración de JVM, cualquier método tiene la capacidad de lanzar una RuntimeException si lo declaras como arrojando Exception o no. La captura/manejo de RuntimeExceptions es generalmente una mala práctica. Si bien hay algunos casos limitados en los que este comportamiento podría ser necesario, RuntimeExceptions es principalmente un indicador de que hay algo mal con el código, en lugar del uso del producto. Por supuesto, un inconveniente importante de la captura de RuntimeExceptions (especialmente si los está ignorando) es que las cosas podrían estar explotando en su sistema y no tiene idea de que está sucediendo ... entonces, de repente, su sistema escupe completamente datos no válidos o bloqueos de cualquier otro motivo, lo que hace más difícil rastrear la causa raíz. tutorial

Ver Sun/Oracle acerca de las excepciones

http://download.oracle.com/javase/tutorial/essential/exceptions/runtime.html

Para responder a la pregunta, a menos que sepa exactamente lo derivado de excepción que puede esperar a estar lanzando, estás Excepción de lanzamiento bastante atrapado, aunque ¿Tiene dudas importantes sobre la utilidad de arrojar la clase de Excepción genérica, a menos que solo le importe cerrar la sesión de seguimiento de la pila y tal que sepa que sucedió? Si intenta manejar robustamente la Excepción sin saber qué tipo de Excepción es, entonces probablemente no tendrá mucho éxito en manejarla adecuadamente o incluso lo suficientemente bien.

+0

Se trata más bien de asegurarse de que el paquete de proveedores no impida que el sistema se ejecute. Este es un marco de plug-in donde se pueden agregar plug-ins de múltiples proveedores según lo deseado. –

1

Puede implementar su interfaz en una clase abstracta que utiliza el patrón de método de plantilla para capturar y ajustar RuntimeExceptions con una excepción personalizada. Sin embargo, no hay forma de exigir que los proveedores usen la clase abstracta (que no sea la documentación).

class MySeviceException extends Exception{ 
    public MySeviceException() {} 
    public MySeviceException(String msg) { super(msg); } 
    public MySeviceException(Throwable cause) { super(cause); } 
    public MySeviceException(String msg, Throwable cause) { super(msg, cause); } 
} 

interface A 
{ 
    void x() throws MySeviceExceptionException; 
    void y() throws MySeviceExceptionException; 
} 

class ABase implements A 
{ 
    public final void x() throws MySeviceExceptionException { 
     try { 
      doX(); 
     } catch(RuntimeException ex) { 
      throw new MySeviceExceptionException(ex); 
     } 
    } 
    public final void y() throws MySeviceExceptionException { 
     try { 
      doY(); 
     } catch(RuntimeException ex) { 
      throw new MySeviceExceptionException(ex); 
     } 
    } 

    public abstract void doX() throws MySeviceExceptionException; 
    public abstract void doY() throws MySeviceExceptionException; 
} 
Cuestiones relacionadas