Riscrivere le eccezioni in Java senza perdere la traccia dello stack


417

In C #, posso usare l' throw;istruzione per riproporre un'eccezione preservando la traccia dello stack:

try
{
   ...
}
catch (Exception e)
{
   if (e is FooException)
     throw;
}

C'è qualcosa di simile in Java ( che non perde la traccia dello stack originale )?


4
Perché pensi che perda lo stacktrace originale? L'unico modo per perderlo quando si lancia SomeOtherException nuovo e si dimentica di assegnare la causa principale nel costruttore o in initCause ().
Akarnokd,

4
Credo che questo sia il modo in cui il codice si comporta in .Net, ma non sono più positivo. Potrebbe essere utile cercarlo da qualche parte o eseguire un piccolo test.
ripper234,

11
Throwablenon vengono modificati lanciandoli. Per aggiornare la traccia dello stack devi chiamare fillInStackTrace(). Convenientemente questo metodo viene chiamato nel costruttore di a Throwable.
Robert,

50
In C #, sì, throw e;perderà lo stacktrace. Ma non in Java.
Tim Goodman,

Risposte:


560
catch (WhateverException e) {
    throw e;
}

ridisegnerà semplicemente l'eccezione che hai colto (ovviamente il metodo circostante deve permetterlo tramite la sua firma ecc.). L'eccezione manterrà la traccia dello stack originale.


4
Salve, InterruptedException e dà un messaggio di eccezione non gestita quando aggiungo la linea di lancio. Non è così se lo sostituisco con l'eccezione più ampia e. Come dovrebbe essere fatto correttamente?
James P.

1
@James, ho appena osservato che il messaggio scompare se si aggiunge "genera XxxException" nella dichiarazione di funzione.
shiouming

2
Nel compilatore Java 7 per tale ripensamento è più intelligente. Ora funziona bene con specifiche "genera" eccezioni nel metodo di contenimento.
Waldemar Wosiński,

193
@James Se questo non catch(Exception e) { throw e; }verrà gestito . Se catch(InterruptedException ie) { throw ie; }verrà gestito. Come regola generale, non farlo catch(Exception e)- questo non è Pokemon, e non vogliamo catturarli tutti!
corsiKa

3
@corsiKa Non è necessariamente vero che non vuoi "catturarli tutti", è solo un caso d'uso diverso. Se si dispone di un loop di livello superiore o di un gestore eventi (ad esempio, all'interno di un thread in esecuzione) se non si rileva almeno RuntimeException e lo si registra, spesso si perde del tutto l'eccezione e si esce silenziosamente da un loop importante per ciò che è spesso un fallimento occasionale. È anche molto utile per la funzionalità del plug-in in cui non sai quale codice aggiuntivo potrebbe fare o lanciare ... Per usi top-down come questi, l'eccezione spesso non è solo una buona idea ma una buona pratica.
Bill K,

82

Preferirei:

try
{
    ...
}
catch (FooException fe){
   throw fe;
}
catch (Exception e)
{
    // Note: don't catch all exceptions like this unless you know what you
    // are doing.
    ...
}

6
Decisamente corretto in Java per rilevare eccezioni specifiche rispetto a quelle generiche e verificando ad esempio di. +1
amischiefr

8
-1 perché non dovresti mai cogliere "Eccezione" se non sai cosa stai facendo.
Stroboskop,

19
@Stroboskop: vero, ma per rispondere è meglio usare lo stesso codice (simile) della domanda!
user85421

14
A volte catturare tutte le eccezioni è ok. Come quando stai scrivendo un test case. O per scopi di registrazione. O soprattutto perché non catturare significa schiantarsi.
John Henckel,

1
@JohnHenckel e altri: punti validi indicati. Ho aggiornato la domanda per chiarire che la cattura in Exceptiongenere non è la cosa giusta da fare, nella maggior parte (ma non in tutti) i casi.
Per Lundberg,

74

Puoi anche racchiudere l'eccezione in un'altra E conservare la traccia dello stack originale passando l'eccezione come Throwable come parametro cause:

try
{
   ...
}
catch (Exception e)
{
     throw new YourOwnException(e);
}

8
Vorrei anche consigliare di aggiungere un messaggio a fianco, utilizzandothrow new YourOwnException("Error while trying to ....", e);
Julien

questo è quello che stavo cercando, in particolare la versione del primo commento in cui puoi passare il tuo messaggio
Csaba

Questo mostra il messaggio di errore correttamente ma la traccia dello stack mostra la linea di errore come linea con 'lancia nuovo ....... (e)' non la linea originale che ha causato l'eccezione.
Ashburn RK,

22

In Java è quasi lo stesso:

try
{
   ...
}
catch (Exception e)
{
   if (e instanceof FooException)
     throw e;
}

5
No, finché non si crea un'istanza di un nuovo oggetto Exception, lo stacktrace rimane lo stesso.
Mnementh,

28
Aggiungerei una cattura specifica per FooException
dfa

3
In questo caso specifico sono d'accordo, ma l'aggiunta di un pescato specifico potrebbe non essere la scelta giusta: immagina di avere un codice comune per tutte le eccezioni e dopo, per una particolare eccezione, ripeterlo.
alves

1
@MarkusLausberg Ma alla fine non coglie eccezioni.
Robert,

Sì, ma questa non era la domanda.
Markus Lausberg,

14

In Java, hai appena lanciato l'eccezione che hai catturato, quindi throw epiuttosto che semplicemente throw. Java mantiene la traccia dello stack.


6

qualcosa come questo

try 
{
  ...
}
catch (FooException e) 
{
  throw e;
}
catch (Exception e)
{
  ...
}

5
public int read(byte[] a) throws IOException {
    try {
        return in.read(a);
    } catch (final Throwable t) {
        /* can do something here, like  in=null;  */
        throw t;
    }
}

Questo è un esempio concreto in cui il metodo genera un IOException. I finalmezzi tpossono contenere solo un'eccezione generata dal blocco try. Materiale di lettura aggiuntivo può essere trovato qui e qui .



3

La traccia dello stack viene riservata se si avvolge l'eccezione catturata in un'altra eccezione (per fornire ulteriori informazioni) o se si ricicla nuovamente l'esclusione catturata.

try{ ... }catch (FooException e){ throw new BarException("Some usefull info", e); }


2

Stavo solo vivendo una situazione simile in cui il mio codice potenzialmente genera una serie di diverse eccezioni che volevo solo ripensare. La soluzione sopra descritta non funzionava per me, perché Eclipse mi ha detto che throw e;porta a un'eccezione non gestita, quindi ho fatto solo questo:

try
{
...
} catch (NoSuchMethodException | SecurityException | IllegalAccessException e) {                    
    throw new RuntimeException(e.getClass().getName() + ": " + e.getMessage() + "\n" + e.getStackTrace().toString());
}

Ha funzionato per me .... :)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.