Domanda

Credo Exception.fillInStackTrace deve restituire eccezioni o oggetti Exception derivati. Considerando le due funzioni di seguito,

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. Il exception handler non ha potuto prendere il new Throwable() nel primo f() funzione.
  2. Il exception handler potrebbe prendere il e.fillInstackTrace() nel secondo g() funzione.
  3. Ma la seconda funzione g() avrebbe ancora bisogno di throws Throwable. Questo è davvero strano, dal momento che abbiamo potuto prendere e.fillInstackTrace().

Quindi la mia domanda è: perché non fa Exception.fillInStackTrace ritorno Exception o eccezione di derivazione invece di sviluppare una sintassi così strana?

Modifica :
Per chiarire la mia domanda: Che cosa intendo per "strana sintassi" sono

  1. Dal riferimento di ritorno Exception.fillInStackTrace() Throwable, il gestore di eccezioni che recieve riferimento Exception non dovrebbe essere in grado di catturare il java exception.Because non consente implict bassi, dovrebbe essere qualcosa di simile a return (Exception)e.fillInstackTrace().
  2. Dal momento che è progettato in modo che il gestore di eccezioni che riceve riferimento Exception potrebbe gestire l'eccezione Throwable, non v'è alcuna necessità di marcare il metodo g() getta Throwable exception.But java compilatore ci avrebbe imporre di farlo.

Grazie.

È stato utile?

Soluzione

In realtà è più facile rispondere alle vostre domande a partire con la domanda 2.

Hai chiesto:    2. Dal momento che è progettato in modo che il riferimento al gestore delle eccezioni eccezioni che riceve in grado di gestire l'eccezione Throwable, non v'è alcuna necessità di marcare il metodo g () throws Throwable exception.But java compilatore ci avrebbe imporre di farlo.

Risposta: In realtà, catch (Exception e) non può prendere un Throwable. Prova questo:

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

Vedrai che la clausola catch non cattura il tiro in questo caso.

La ragione per cui la clausola catch funziona nel metodo g () è che quando si richiama throw e.fillInStackTrace(), la chiamata a fillInStackTrace in realtà restituisce un'eccezione (che è perché e è un'eccezione stesso). Dal momento che l'eccezione è una sottoclasse di Throwable, che non contraddice la dichiarazione di fillInStackTrace.

Ora al primo quesito

Hai chiesto:    1. Poiché Exception.fillInStackTrace () di ritorno di riferimento Throwable, il gestore di eccezioni che recieve riferimento eccezione non dovrebbe essere in grado di catturare il java exception.Because non consente implict bassi, dovrebbe essere qualcosa di simile ritorno (Exception) e.fillInstackTrace () .

Risposta: Questo non è esattamente un abbattuta implicita. Pensate a questo come una variante del sovraccarico.

Diciamo che hai

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

Se si chiama process(someObject), esso sarà determinato in fase di esecuzione se il primo o il secondo metodo viene chiamato processo. Allo stesso modo, se la clausola catch (Exception e) in grado di catturare il tiro sarà determinato in fase di esecuzione, a seconda se si lancia un'eccezione o Throwable.

Altri suggerimenti

Sono piuttosto perplesso la tua domanda. C'è chiaramente qualcosa sulle eccezioni Java / gestione delle eccezioni che non si capisce. Così iniziamo dal principio.

In Java, tutte le eccezioni (nel senso che questo termine viene usato nel linguaggio Java Specification) sono istanze di una certa classe che è una sottoclasse di java.lang.Throwable. Ci sono due (e solo due) sottoclassi diretti di Throwable; cioè java.lang.Exception e java.lang.Error. Le istanze di tutte queste classi ... tra cui le istanze di Throwable and Error ... sono indicati come eccezioni nella JLS.

Un gestore di eccezioni cattura eccezioni (nel senso JLS) che sono compatibili con l'assegnazione del tipo di eccezione utilizzato nella dichiarazione catch. Così, per esempio:

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

cattura qualsiasi eccezione gettato nel blocco try che è un'istanza di java.lang.Exception o di un sottotipo diretta o indiretta di java.lang.Exception. Ma non prenderà un'istanza di java.lang.Throwable, perché è (ovviamente) non è uno di cui sopra.

D'altra parte:

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

prendere un'istanza di java.lang.Throwable.

Rivedere il vostro esempio alla luce di questo, è ovvio il motivo per cui il metodo f non sta recuperando l'istanza Throwable: essa non corrisponde al tipo di eccezione nella clausola catch! Al contrario, nel metodo g l'istanza di eccezione abbinato il tipo di eccezione nella clausola cattura e rientra quindi.

Non capisco quello che dici circa la necessità di gettare un Throwable in g. In primo luogo, il fatto che il metodo dichiara che getta Throwable non significa che in realtà ha bisogno di buttarlo. Tutto quello che sta dicendo è che potrebbe gettare qualcosa assegnabile a Throwable ... forse in qualche futura versione del metodo g. In secondo luogo, se si dovesse aggiungere throw e; al blocco catch esterna, è sarebbe da buttare qualcosa che è assegnabile a Throwable.

Infine, è generalmente una cattiva idea quella di essere la creazione di istanze di Throwable, Eccezione, errore e RuntimeException. Ed è necessario essere molto attenti quando e come si cattura. Ad esempio:

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, 
}

Modifica - nei commenti la risposta di OP:

  

Ma cosa butto con lancio e.fillInStackTrace (); dovrebbe essere un intance di Throwable, non fa eccezione!

Il Javadoc dice espressamente che l'oggetto restituito è l'oggetto eccezione che si sta chiamando il metodo su. Lo scopo del metodo è quello di riempire fillInStacktrace() nella traccia stack per un oggetto esistente. Se si desidera un un'eccezione diversa, è necessario utilizzare new per creare uno.

  

In realtà, voglio dire il gestore di eccezioni outter non dovrebbe prendere il Throwable gettato da tiro e.fillInStackTrace ().

ho spiegato il motivo per cui lo fa - perché la Throwable è in realtà l'eccezione originale. C'è qualcosa circa la mia spiegazione che non si capisce o siete semplicemente dicendo che non ti piace il modo in cui Java è definito?

Modifica 2

  

E se il gestore di eccezioni outter in grado di gestire l'eccezione Throwable, perché dobbiamo precisare che il metodo g getterebbe eccezione Throwable

frainteso quello che stavo dicendo ... che era che se avete fatto lancerà un'eccezione, allora il throws Throwable non sarebbe ridondante. OTOH, ho finalmente credo di capire il suo reclamo.

Penso che il punto cruciale della vostra lamentela è che si otterrebbe un errore di compilazione con questo:

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.
    }
}

Posso capire che questo è un po 'inaspettato. Ma è inevitabile ho paura. Non c'è modo (a corto di un cambiamento importante al sistema di tipo Java) che si potrebbe dichiarare il SIgnature del fillInStacktrace che funziona in tutti i casi. Ad esempio, se si è spostato la dichiarazione del metodo alla classe Exception, si era appena ripetere lo stesso problema con sottotipi di Exception. Ma se si è tentato di esprimere la firma utilizzando un parametro di tipo generico, che comporterebbe facendo tutte le sottoclassi di tipi generici espliciti Throwable.

Per fortuna, la cura è molto semplice; il cast del risultato di fillInStacktrace() come segue:

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

E l'ultimo punto è che è molto insolito per un'applicazione di chiamare in modo esplicito fillInStacktrace(). Alla luce di questo, sarebbe semplicemente non sono stati utile per i progettisti di Java per avere "rotto il loro coraggio", cercando di risolvere questo problema. Soprattutto dal momento che è in realtà solo un piccolo inconveniente ... al massimo.

Credo che avrei dovuto chiedere a Frank Yellin (la @author di java.lang.Exception). Come altri hanno detto, fillInStackTrace() viene dichiarata in Throwable e documentata per tornare this, per cui il suo tipo di ritorno deve essere Throwable. E 'solo ereditato da Exception. Frank avrebbe potuto sovrascritto in Exception, in questo modo:

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

... ma non lo fece. Prima di Java 1.5, il motivo è che avrebbe prodotto un errore di compilazione. In 1,5 e oltre, covariante ritorno tipi permessi e quanto sopra è legale.

Ma la mia ipotesi è che se l'override sopra esisteva, si sarebbe poi chiedere perché RuntimeException non ha un override di simile, perché ArrayStoreException non sostituisce quella di override, e via dicendo. Così Frank e gli amici probabilmente solo non volevano scrivere quelle centinaia di sostituzioni identici.

Vale la pena notare che, se hai a che fare con le proprie classi di eccezioni personalizzate, si può facilmente ignorare il metodo fillinStackTrace() come ho fatto in precedenza, e ottenere il tipo più stretto che stai cercando.

Utilizzando farmaci generici, si potrebbe immaginare aumentando la dichiarazione di Throwable a:

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

... ma che non è proprio soddisfacente, per ragioni che sono oltre la portata di questa risposta.

fillInStackTrace ritorna il riferimento allo stesso oggetto. E 'il metodo di concatenamento per consentire ri-lanciare la Exception e la reimpostazione dello stack di eccezione.

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();
    }
}

Il tipo di ritorno del metodo può essere solo tipo di base che è Throwable. Si può generified in modo che il metodo restituisce il tipo parametrizzata. Ma non è il caso, per ora.

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() è definito da Throwable, non Exception.

Non tutte le sottoclassi di Throwable sono eccezioni (Error, per esempio). Per quanto riguarda la Throwable è interessato, l'unica cosa che può garantire circa il valore di ritorno di fillInStackTrace() è che è un esempio di Throwable (dal momento che solo restituisce lo stesso oggetto, come Chandra Patni ha osservato).

In realtà fillInStackTrace restituisce lo stesso oggetto è stato invocato su.

e.fillInStackTrace == e è sempre vero

E 'solo un collegamento , si può anche solo scrivere

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

o utilizzare un cast

    throw (Exception) e.fillInStackTrace();

A proposito, lo stesso accade con initCause().

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top