2011-02-16 21 views
12

No entiendo las ventajas de tener una excepción encadenada en el código.Cuál es la ventaja de las excepciones encadenadas

Teniendo en cuenta el ResourceLoader example from java world, si el programador sabe de una posibilidad de encontrar ResourceLoadException, por qué no coger la misma excepción en lugar de SQLException? De lo contrario, el programador puede detectar ambas excepciones en el mismo código que tener que lanzar una nueva instancia de Throwable.

Respuesta

15

¿Puede alguien proporcionar información sobre la necesidad de excepciones encadenadas?

El artículo dice bastante bien:

Excepción encadenamiento permite asignar un tipo de excepción a otra, por lo que un método puede lanzar excepciones definidas en el mismo nivel de abstracción como el propio método , sin descartar información importante de depuración.

Es decir, si usted tiene un método que carga un objeto a partir de una base de datos, es posible que en lugar que desee alguna ResourceLoadException (más cerca relacionado con el nivel de abstracción métodos) en lugar de un bajo nivel de SQLException incluso si ese era el fuente original del problema Sin embargo, si simplemente captura el SQLException y tira un ResourceLoadException, puede perder información importante de depuración.

Por lo tanto, encadenar las excepciones es una buena alternativa. Lanzas una excepción de "alto nivel", muy adecuada para el método particular, pero la encadenas con la excepción que la causó.

lo demás, el programador puede atrapar tanto las excepciones en el mismo código de tener que lanzar una nueva instancia Throwable?

No acabo de seguir su razonamiento aquí. El punto es que no debería tener que preocuparse por el SQLException en este nivel de abstracción.

+0

ok Mi punto era: ¿qué pasaría con los siguientes cambios (que muestran solo los cambios necesarios aquí)? 'try {} catch (SQLException e) {} catch (ResourceLoadException f) {}'. Pero entiendo tu punto sobre tener una Excepción más cercanamente relacionada. Pero ahora mi pregunta sería, si la excepción personalizada no tiene nada que ver con la excepción real causada, es decir, si la excepción en realidad es 'SQLException' y no' ResourceLoadException', que el código de manejo de excepciones podría ser un error? –

+2

Nada estaría * mal * con ese cambio de código, pero como dije, puede no tener ningún sentido, tener que atrapar 'SQLException' en ese nivel de abstracción. ¿Qué ocurre si, por ejemplo, hay dos clases de carga de recursos: 'MysqlResourceLoader' y' FileResourceLoader' y comparten una interfaz común, 'ResourceLoader'. Entonces el método 'loadResource' obviamente no debería declararse para lanzar' SQLException'. (¿Qué sucede si le doy un 'ResourceLoader' y no sabe si es del tipo real?) – aioobe

+3

El punto es que puede tener una interfaz que arroje un tipo de excepción específico en el nivel de abstracción. En la implementación de esa interfaz puede ser necesario capturar una SQLException o de lo contrario. El objetivo de una interfaz es quedarse con ella y no tener que cambiarla, sin importar cuál sea la esencia de la implementación ... si eso tiene sentido. Además, en este caso, la clase principal no tendrá idea de qué hacer con una SQLException. Lo único que tiene que hacer es concluir "estamos jodidos", imprimir un error y hacer que el usuario lo solucione. – user606723

1

Creo que el motivo de esa muestra es que el autor desea crear una interfaz uniforme que no dependa de un sistema subyacente específico, como SQL. Por lo tanto, convierte la excepción a la forma más general, dejando la implementación real transparente para la lógica comercial.

Sin embargo, en algunos casos puede ser conveniente propagar un error como SQLException. Esto será útil en lugares donde se necesita tomar diferentes acciones basadas en la Excepción lanzada.

5

La ventaja es que la persona que llama solo tiene que manejar un ResourceLoadException en lugar de SQLException. De esta forma, si más tarde cambia su almacenamiento de datos para que esté en un archivo, acceder a él podría causar IOException. No tiene que volver atrás y cambiar el tipo de Excepción que maneja su interlocutor. Esto es útil para quien llama porque la persona que llama va a manejar cualquiera de las dos excepciones de la misma manera.

5

Una persona que llama al loadResource no debería necesitar conocer los detalles exactos de cómo se cargan esos recursos, o al menos no se preocupan por los detalles de por qué falló. (Tenga en cuenta que podría no ser usted quien escribió loadResources, o podría ser otra persona la que necesite usar el método loadResources).

Todo lo que debe tener en cuenta al llamar a loadResource es que podría arrojar una excepción ResourceLoadException. No es que los detalles de implementación fallen debido a una excepción SQLException, esto también puede cambiar con el tiempo, más tarde alguien podría decidir cargar recursos de otro lugar que también podrían fallar.

Solo necesita cargar algunos recursos, necesita manejarlos si falla, y no manejar las posibles MainframeHasCrashedException, FileNotFoundException y la docena de otras razones por las que cargar esos recursos podría fallar.

Ahora, cuando algo falla, es útil tener la excepción original que causó el error, como una excepción de SQL - por lo que alguien fregar a través de archivos de registro o similar puede averiguar la causa del error mediante la inspección de la StackTrace

No debería caer en la tentación de simplemente capturar Exception aquí, si loadResources también podría arrojar otras excepciones, por ejemplo una UnautorizedException, es posible que no desee tratar con eso cuando llame a loadResources; es posible que desee propagar esa excepción a otras personas que llamen que puedan tratar con UnautorizedException (y tal vez soliciten al usuario algunas credenciales). un catch (Exception e) se tragaría esa UnautorizedException con la que realmente no puedes lidiar.

+0

¡Gracias por la explicación! –

2

El primer beneficio es la encapsulación. ResourceLoader podría ser una interfaz con varias implementaciones (por ejemplo, una que cargue los recursos de la base de datos, mientras que otra los carga desde el sistema de archivos), donde la implementación a usar se selecciona en tiempo de ejecución. Entonces la persona que llama debe ser independiente de la causa raíz de por qué no se pudo cargar el recurso, pero aún así podría desear reaccionar ante fallas en la carga de recursos. Esto es particularmente útil si la interfaz declara dos excepciones diferentes a las que la persona que llama podría desear responder de manera diferente (por ejemplo, una TransientResourceLoadFailureException, donde podría producirse un reintento, y PermanentResourceLoadFailureException, donde se sabe que un reintento no tiene éxito).

El segundo beneficio del encadenamiento de excepciones es que cada excepción en la cadena puede tener un mensaje diferente, lo que permite incluir información adicional para la depuración. En su caso, tenga en cuenta que el mensaje ResourceLoadException contiene el nombre del recurso que no se pudo cargar, que no está garantizado para ser incluido en la excepción SQLException, pero podría ser necesario para reproducir el problema (ciertas bases de datos no son exactamente conocidas por error específico) mensajes).

Estos beneficios tienen el costo de tener que escribir y mantener los bloques de captura. Debe decidir caso por caso si los beneficios justifican el costo.

+0

tiene sentido. Gracias por la explicación !! –

11

¿Por qué Chain exception?

Tenemos que encadenar las excepciones para que los registros sean legibles.

Take siguientes ejemplos de 1. Sin encadenamiento y 2. encadenamiento, excepciones a sentir la diferencia

Crear siguientes excepciones

class NoLeaveGrantedException extends Exception { 

     public NoLeaveGrantedException(String message, Throwable cause) { 
      super(message, cause); 
     } 

     public NoLeaveGrantedException(String message) { 
      super(message); 
     } 
    } 

    class TeamLeadUpsetException extends Exception { 

     public TeamLeadUpsetException(String message, Throwable cause) { 
      super(message, cause); 
     } 

     public TeamLeadUpsetException(String message) { 
      super(message); 
     } 
    } 

    class ManagerUpsetException extends Exception { 

     public ManagerUpsetException(String message, Throwable cause) { 
      super(message, cause); 
     } 

     public ManagerUpsetException(String message) { 
      super(message); 
     } 
    } 

    class GirlFriendOfManagerUpsetException extends Exception { 

     public GirlFriendOfManagerUpsetException(String message, Throwable cause) { 
      super(message, cause); 
     } 

     public GirlFriendOfManagerUpsetException(String message) { 
      super(message); 
     } 
    } 

Ahora ellos

1 utilizar. Sin encadenar

public class MainClass { 

     public static void main(String[] args) throws Exception { 
      getLeave(); 
     } 

     static void getLeave() throws NoLeaveGrantedException { 
      try { 
       howIsTeamLead(); 
      } catch (TeamLeadUpsetException e) { 
       e.printStackTrace(); 
       throw new NoLeaveGrantedException("Leave not sanctioned."); 
      } 
     } 

     static void howIsTeamLead() throws TeamLeadUpsetException { 
      try { 
       howIsManager(); 
      } catch (ManagerUpsetException e) { 
       e.printStackTrace(); 
       throw new TeamLeadUpsetException(
          "Team lead is not in good mood"); 
      } 
     } 

     static void howIsManager() throws ManagerUpsetException { 
      try { 
       howIsGirlFriendOfManager(); 
      } catch (GirlFriendOfManagerUpsetException e) { 
       e.printStackTrace(); 
       throw new ManagerUpsetException("Manager is in bad mood"); 
      } 

     } 

     static void howIsGirlFriendOfManager() 
      throws GirlFriendOfManagerUpsetException { 
      throw new GirlFriendOfManagerUpsetException(
      "Girl friend of manager is in bad mood"); 
     } 
    } 

2.Encadenando

public class MainClass { 

     public static void main(String[] args) throws Exception { 
      getLeave(); 
     } 

     static void getLeave() throws NoLeaveGrantedException { 
      try { 
       howIsTeamLead(); 
      } catch (TeamLeadUpsetException e) { 
       throw new NoLeaveGrantedException("Leave not sanctioned.", e); 
      } 
     } 

     static void howIsTeamLead() throws TeamLeadUpsetException { 
      try { 
       howIsManager(); 
      } catch (ManagerUpsetException e) { 
       throw new TeamLeadUpsetException(
          "Team lead is not in good mood", e); 
      } 
     } 

     static void howIsManager() throws ManagerUpsetException { 
      try { 
       howIsGirlFriendOfManager(); 
      } catch (GirlFriendOfManagerUpsetException e) { 
       throw new ManagerUpsetException("Manager is in bad mood", e); 
      } 

     } 

     static void howIsGirlFriendOfManager() 
      throws GirlFriendOfManagerUpsetException { 
      throw new GirlFriendOfManagerUpsetException(
       "Girl friend of manager is in bad mood"); 
     } 
    } 

Ahora compara los registros de

1. Sin encadenamiento

com.bskyb.svod.autoingest.GirlFriendOfManagerUpsetException: Girl friend of manager is in bad mood 
     at com.bskyb.svod.autoingest.MainClass.howIsGirlFriendOfManager(MainClass.java:61) 
     at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:52) 
     at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:43) 
     at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34) 
     at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29) 
    com.bskyb.svod.autoingest.ManagerUpsetException: Manager is in bad mood 
     at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:55) 
     at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:43) 
     at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34) 
     at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29) 
    com.bskyb.svod.autoingest.TeamLeadUpsetException: Team lead is not in good mood 
     at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:46) 
     at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34) 
     at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29) 
    Exception in thread "main" com.bskyb.svod.autoingest.NoLeaveGrantedException: Leave not sanctioned. 
     at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:37) 
     at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29) 

2. encadenar

Exception in thread "main" com.bskyb.svod.autoingest.NoLeaveGrantedException: Leave not sanctioned. 
     at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:36) 
     at com.bskyb.svod.autoingest.MainClass.main(MainClass.java:29) 
    Caused by: com.bskyb.svod.autoingest.TeamLeadUpsetException: Team lead is not in good mood 
     at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:44) 
     at com.bskyb.svod.autoingest.MainClass.getLeave(MainClass.java:34) 
     ... 1 more 
    Caused by: com.bskyb.svod.autoingest.ManagerUpsetException: Manager is in bad mood 
     at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:52) 
     at com.bskyb.svod.autoingest.MainClass.howIsTeamLead(MainClass.java:42) 
     ... 2 more 
    Caused by: com.bskyb.svod.autoingest.GirlFriendOfManagerUpsetException: Girl friend of manager is in bad mood 
     at com.bskyb.svod.autoingest.MainClass.howIsGirlFriendOfManager(MainClass.java:58) 
     at com.bskyb.svod.autoingest.MainClass.howIsManager(MainClass.java:50) 
     ... 3 more 
+1

Me encanta la manera en que tu ejemplo demostró encadenamiento. Se rió mucho –

Cuestiones relacionadas