Pregunta

Creo que Exception.fillInStackTrace debería devolver Exception o objetos Exception derivados.Considerando las dos funciones siguientes,

public static void f() throws Throwable {
    try {
        throw new Throwable();
    } catch (Exception e) {
        System.out.println("catch exception e");
        e.printStackTrace();
    } 
}
public static void g() throws Throwable {
    try {
        try {
            throw new Exception("exception");
        } catch (Exception e) {
            System.out.println("inner exception handler");
            throw e.fillInStackTrace();
        }
    } catch (Exception e) {
        System.out.println("outer exception handler");
        e.printStackTrace();
    }
}
  1. El exception handler no pudo atrapar el new Throwable() en la primera función f().
  2. El exception handler podría atrapar el e.fillInstackTrace() en la segunda funcion g().
  3. Pero la segunda función g() todavía necesitaría throws Throwable.Esto es realmente extraño, ya que pudimos captar e.fillInstackTrace().

Entonces mi pregunta es ¿por qué Exception.fillInStackTrace no devuelve Exception o Exception-derived en lugar de desarrollar una sintaxis tan extraña?

EDITAR:
A aclarar mi pregunta:Lo que quiero decir con "sintaxis extraña" es

  1. Desde Exception.fillInStackTrace() devolver Throwable referencia, el controlador de excepciones que recibe Exception La referencia no debería poder detectar la excepción. Debido a que Java no permite el abatimiento implícito, debería ser algo como return (Exception)e.fillInstackTrace().
  2. Dado que está diseñado para que el controlador de excepciones que recibe Exception referencia podría manejar el Throwable excepción, no es necesario marcar el método g() lanza Throwable excepción, pero el compilador de Java nos obligaría a hacerlo.

gracias.

¿Fue útil?

Solución

En realidad, es más fácil responder sus preguntas comenzando con la pregunta 2.

Tu preguntaste:2.Dado que está diseñado para que el controlador de excepciones que recibe la referencia de Excepción pueda manejar la excepción Throwable, no es necesario marcar el método g() para lanzar la excepción Throwable, pero el compilador de Java nos obligaría a hacerlo.

Respuesta:En realidad, catch (Excepción e) no puede capturar un Throwable.Prueba esto:

try {
       Throwable t = new Throwable();
       throw t.fillInStackTrace();
} catch (Exception e) {
    System.out.println("outer exception handler");
    e.printStackTrace();
} 

Verás que la cláusula catch no atrapa el lanzamiento en este caso.

La razón por la que la cláusula catch funciona en su método g() es que cuando invoca throw e.fillInStackTrace(), la llamada a fillInStackTrace en realidad devuelve una excepción (eso se debe a que e es una excepción en sí misma).Dado que Exception es una subclase de Throwable, eso no contradice la declaración de fillInStackTrace.

Ahora a la primera pregunta.

Tu preguntaste:1.Dado que Exception.fillInStackTrace() devuelve una referencia Throwable, el controlador de excepciones que recibe la referencia de excepción no debería poder detectar la excepción. Debido a que Java no permite el abatimiento implícito, debería ser algo así como return (Exception)e.fillInstackTrace().

Respuesta:Esto no es exactamente un abatimiento implícito.Piense en esto como una variación de la sobrecarga.

digamos que tienes

void process(Throwable t){
   ...
}
void process(Exception e){
  ...
} 

si llamas process(someObject), se determinará en tiempo de ejecución si se llama al primer o segundo método de proceso.De manera similar, si la cláusula catch(Exception e) puede o no capturar su lanzamiento se determinará en tiempo de ejecución, en función de si lanza una excepción o un Throwable.

Otros consejos

Estoy bastante desconcertado por su pregunta. Hay claramente algo acerca de las excepciones de Java / manejo de excepciones que usted no entiende. Así que vamos a empezar por el principio.

En Java, todas las excepciones (en el sentido de que este término se utiliza en la especificación del lenguaje Java) son instancias de una cierta clase que es una subclase de java.lang.Throwable. Hay dos (y sólo dos) subclases de Throwable directos; es decir java.lang.Exception y java.lang.Error. Los casos de todas estas clases ... incluyendo casos de Throwable y error ... se conocen como excepciones en el JLS.

Un controlador de excepciones atrapa excepciones (en el sentido JLS) que son asignación compatible con el tipo de excepción usado en la declaración catch. Así, por ejemplo:

try {
    ....
} catch (Exception ex) {
    ...
}

cogerá cualquier excepción lanzada en el bloque try que es una instancia de java.lang.Exception o de un subtipo directa o indirecta de java.lang.Exception. Pero no va a coger una instancia de java.lang.Throwable, porque eso es (obviamente) no uno de los anteriores.

Por otro lado:

try {
    ....
} catch (Throwable ex) {
    ...
}

atrapar una instancia de java.lang.Throwable.

Revisión de su ejemplo a la luz de esto, es evidente por qué el método f no está alcanzando la instancia Throwable: no coincide con el tipo de excepción en la cláusula catch! Por el contrario, en el método g la instancia Excepción juego con el tipo de excepción en la cláusula de captura y por lo tanto es capturado.

No entiendo lo que está diciendo sobre la necesidad de lanzar un Throwable en g. En primer lugar, el hecho de que el método declara que lanza Throwable no significa que lo que realmente necesita para lanzarla. Todo lo que está diciendo es que podría tirar algo asignable a throwable ... posiblemente en alguna versión futura del método g. En segundo lugar, si tuviera que añadir throw e; al bloque catch exterior, que haría estar lanzando algo que es asignable a throwable.

Por último, es generalmente una mala idea estar creando instancias de Throwable, Excepción, de errores y RuntimeException. Y hay que tener mucho cuidado cuándo y cómo los captura. Por ejemplo:

try {
     // throws an IOException if file is missing
    InputStream is = new FileInputStream("someFile.txt");
    // do other stuff
} catch (Exception ex) {
    System.err.println("File not found");
    // WRONG!!!  We might have caught some completely unrelated exception;
    // e.g. a NullPointerException, StackOverflowError, 
}

Editar - en los comentarios de OP respuesta:

  

Pero lo lanzo con e.fillInStackTrace tiro (); debe ser un intance de Throwable, no es la excepción!

El Javadoc dice específicamente que el objeto devuelto es el objeto de excepción que está llamando el método sucesivamente. El propósito del método fillInStacktrace() es llenar en el seguimiento de la pila para un objeto existente. Si quieres una excepción diferente, usted debe utilizar new para crear una.

  

En realidad, me refiero a la gestión de excepciones Outter no debe coger el Throwable lanzada por e.fillInStackTrace tiro ().

he explicado por qué lo hace - porque el Throwable es en realidad la excepción original. ¿Hay algo en mi explicación de que usted no entiende o está simplemente diciendo que no le gusta la forma en que Java se define?

EDIT 2

  

Y si el manejador de excepciones Outter podría manejar la excepción Throwable, ¿por qué debemos especificar que el método g tiraría excepción Throwable

Se entiende mal lo que estaba diciendo ... que era que si se hizo lanzar una excepción, entonces el throws Throwable no sería redundante. Otoh, finalmente creo que entiendo su queja.

Creo que el quid de su queja es que no puedes encontrar un error de compilación con esto:

public void function() throws Exception {
    try {
        throw new Exception();
    } catch (Exception ex) {
        throw ex.fillInStackTrace();
        // according to the static type checker, the above throws a Throwable
        // which has to be caught, or declared as thrown.  But we "know" that the 
        // exception cannot be anything other than an Exception.
    }
}

Puedo ver que esto es algo inesperado. Pero es inevitable me temo. No hay manera (por debajo de un cambio importante en el tipo de sistema de Java) que se puede declarar el SIgnature del fillInStacktrace que funcionará en todos los casos. Por ejemplo, si ha movido la declaración del método a la clase de excepción, usted sólo tiene que repetir el mismo problema con los subtipos de Excepción. Pero si se trató de expresar la firma utilizando un parámetro de tipo genérico, que implicaría que fueran todas las subclases de tipos genéricos explícitas Throwable.

Afortunadamente, la cura es muy simple; emitir el resultado de fillInStacktrace() como sigue:

public void function() throws Exception {
    try {
        throw new Exception();
    } catch (Exception ex) {
        throw (Exception) (ex.fillInStackTrace());
    }
}

Y el punto final es que es muy raro que una aplicación para llamar explícitamente fillInStacktrace(). A la luz de esto, sería simplemente no han merecido la pena para los diseñadores de Java para tener "reventado sus entrañas" tratando de resolver esto. Sobre todo porque es realmente sólo un inconveniente menor ... como máximo.

Creo que tendría que preguntar a Frank Yellin (el @author de java.lang.Exception). Como han dicho otros, fillInStackTrace() se declara en Throwable y documentado para volver this, por lo que su tipo de retorno debe ser Throwable. Es sólo heredado por Exception. Frank podría haber anulado en Exception, como esto:

public class Exception extends Throwable{
    /**Narrows the type of the overridden method*/
    @Override
    public synchronized Exception fillInStackTrace() {
        super.fillInStackTrace();
        return this;
    }
}

... pero no lo hizo. Antes de Java 1.5, la razón es que se habría producido un error de compilación. En 1,5 y más allá, covariante volver tipos están permitidos y lo anterior es legal.

Pero mi suposición es que si existía la anulación anterior, debería entonces preguntar por qué RuntimeException no tiene una anulación similares, ¿por qué no anula ArrayStoreException que invalidación, y así sucesivamente. Así que Frank y amigos probablemente no quieren escribir esos cientos de reemplazos idénticos.

Vale la pena señalar que, si usted está tratando con sus propias clases de excepción personalizada, puede modificar fácilmente el método fillinStackTrace() como lo he hecho anteriormente, y obtener el tipo más estrecho que el que está buscando.

El uso de los genéricos, uno podría imaginar aumentar la declaración de Throwable a:

public class Throwable<T extends Throwable<T>>{
    public synchronized native T fillInStackTrace();
}

... pero eso no es realmente satisfactoria, por razones que están más allá del alcance de esta respuesta.

fillInStackTrace devuelve la referencia al mismo objeto. Es el método de encadenamiento para permitir la re-lanzando el Exception y restablecer seguimiento de la pila de excepción.

public static void m() {
    throw new RuntimeException();

}

public static void main(String[] args) throws Throwable {
    try {
        m();
    } catch (Exception e) {
        e.printStackTrace();
        throw e.fillInStackTrace();
    }
}

El tipo de retorno método sólo puede ser de tipo de base que es Throwable. Se puede generified por lo que el método devuelve el tipo parametrizado. Pero eso no es el caso, por ahora.

RuntimeException e = new RuntimeException();
Throwable e1 = e.fillInStackTrace();
System.out.println(e1.getClass().getName()); //prints java.lang.RuntimeException
System.out.println(e == e1); //prints true

fillInStackTrace() se define por Throwable, no Exception.

No todas las subclases de Throwable son excepciones (Error, por ejemplo). En lo que se refiere a Throwable, lo único que puede garantizar sobre el valor de retorno de fillInStackTrace() es que es una instancia de Throwable (ya que sólo devuelve el mismo objeto, como Chandra Patni indique lo contrario).

En realidad fillInStackTrace devuelve el mismo objeto se invoca en.

e.fillInStackTrace == e es siempre verdad

Es sólo un acceso directo , también puede simplemente escribir

    } catch (Exception e) {
        System.out.println("inner exception handler");
        e.fillInStackTrace();
        throw e;
    }

o usar un yeso

    throw (Exception) e.fillInStackTrace();

BTW, lo mismo sucede con initCause().

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top