2012-02-10 15 views
5

He encontrado algunos lugares en las bibliotecas de Java que estoy construyendo en contra de donde la causa de una excepción se establece en la propia excepción.¿Hay alguna razón para establecer la causa de la excepción en sí misma?

¿Hay alguna razón para que la excepción se refiera a sí misma como su causa?

EDITAR

a lo solicitado, aquí es un ejemplo concreto:

enter image description here

+2

Mala práctica de codificación, si la excepción ya es la causa, no tiene que definir una causa principal. –

+3

Claro ... si * desea * crear una dependencia circular de la que no haya escapatoria. De alguna manera estoy pensando que el código no está haciendo lo que crees que está haciendo. –

+0

También es una mala práctica, pero puede suceder que un código atrape la Excepción X y arroje una nueva Excepción X, con la anterior como causa. Entonces pueden parecer similares, pero en realidad son excepciones diferentes. – Luciano

Respuesta

2

No, es solo un mal diseño. Si la excepción es la causa raíz, no necesita definir una causa.

Una excepción que tiene una causa es un caso legítimo para diferentes envoltorios de excepción. Por ejemplo, si crea un almacenamiento de persistencia, es posible que desee lanzar PersistenceExcpetion. Entonces, si es un almacén de archivos, puede hacer que la causa sea una IOException. Si se trata de una base de datos, tal vez la causa sea una SqlException. Etc

3

De las fuentes de Throwable tengo aquí:

public synchronized Throwable initCause(Throwable cause) { 
    ... 
    if (cause == this) 
     throw new IllegalArgumentException("Self-causation not permitted"); 
    ... 
} 

no veo cómo establecer la causa para sí mismo es posible en absoluto.

+0

IIRC, cuando he visto esto, ha estado en excepciones específicas de la capa ORM. No hay razón para creer que debido a que 'Throwable' no lo permite en el método' initCause', las excepciones que he visto se comportan de la misma manera. – arootbeer

+0

Consulte la respuesta de Pierre Henry para ver cómo es posible. – ctomek

7

Frecuentemente he visto excepciones lanzadas por frameworks o bibliotecas como Hibernate o Spring como la causa (confundiendo la GUI del depurador en el proceso).

Siempre me pregunté por qué lo hicieron, ya que parece una mala idea. Y hoy en realidad causó un problema cuando estaba tratando de serializar uno para JSON: bam, enless cycle.

Así que investigué un poco más allá:

En el código fuente de Throwable (todo el código fuente que aparece aquí es de JDK 1.7) tenemos:

/** 
    * The throwable that caused this throwable to get thrown, or null if this 
    * throwable was not caused by another throwable, or if the causative 
    * throwable is unknown. If this field is equal to this throwable itself, 
    * it indicates that the cause of this throwable has not yet been 
    * initialized. 
    * 
    * @serial 
    * @since 1.4 
    */ 
    private Throwable cause = this; 

Ahora se reunió específicamente el problema con una clase de excepción que extendió RuntimeException, así que fui desde allí. Uno de los constructores de RuntimeException:

/** Constructs a new runtime exception with the specified detail message. 
    * The cause is not initialized, and may subsequently be initialized by a 
    * call to {@link #initCause}. 
    * 
    * @param message the detail message. The detail message is saved for 
    *   later retrieval by the {@link #getMessage()} method. 
    */ 
    public RuntimeException(String message) { 
     super(message); 
    } 

Constructor de Exception llamado por el anterior:

/** 
    * Constructs a new exception with the specified detail message. The 
    * cause is not initialized, and may subsequently be initialized by 
    * a call to {@link #initCause}. 
    * 
    * @param message the detail message. The detail message is saved for 
    *   later retrieval by the {@link #getMessage()} method. 
    */ 
    public Exception(String message) { 
     super(message); 
    } 

Constructor de Throwable llamados por lo anterior:

/** 
    * Constructs a new throwable with the specified detail message. The 
    * cause is not initialized, and may subsequently be initialized by 
    * a call to {@link #initCause}. 
    * 
    * <p>The {@link #fillInStackTrace()} method is called to initialize 
    * the stack trace data in the newly created throwable. 
    * 
    * @param message the detail message. The detail message is saved for 
    *   later retrieval by the {@link #getMessage()} method. 
    */ 
public Throwable(String message) { 
    fillInStackTrace(); 
    detailMessage = message; 
} 

fillInStackTrace es un método nativo y no parece modificar el campo de causa.

Como puede ver, a menos que se llame posteriormente al método initCause, el campo cause nunca cambia del valor original de .

Conclusión: si no un nuevo Exception (o una de las muchas muchas subclases que existen en la naturaleza y no invalidar este comportamiento) usando un constructor que no toma un argumento cause, y lo hace crear llama al método initCause, la causa de la excepción será ella misma.

Supongo que debería ser una ocurrencia muy común.

+1

Usted puede crear una excepción autoexplicativa haciendo 'Exception ex = new RuntimeException (" ex ");' Pero 'ex.equals (ex.getCause())' todavía devolverá 'false' debido a' Throwable 'implementation:' return this.cause == this? null: this.cause; ' – Vladimir

7

La respuesta aceptada es engañosa, y las demás respuestas están incompletas. Entonces ...

Si bien sería mal diseño para pasar en una excepción como su propia causa, no es posible en la implementación de Throwable exactamente por ese motivo. La causa se transfiere durante la construcción, o bien al método initCause(), y como se señala en la segunda respuesta, este último daría lugar a una IllegalArgumentException.

Como señala la tercera respuesta, si no proporciona una causa, la causa será este según la implementación de Throwable.

Lo que tal vez falte (dada la pregunta original) es que el método getCause() de Throwable nunca devuelve este, devuelve nulo si causa == esto. Entonces, aunque su depurador muestre el esta referencia como la causa porque está utilizando la reflexión, al usar la interfaz pública de Throwable no lo verá y no será un problema.

Cuestiones relacionadas