prova / cattura e lancia Eccezione


117

Queste istruzioni in codice sono equivalenti? C'è qualche differenza tra loro?

private void calculateArea() throws Exception {
    ....do something
}

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

3
Non è proprio una risposta, ma potresti essere interessato all'articolo di Ned Batchelder Exceptions in the Rainforest , che aiuta a spiegare i casi generali in cui uno stile o l'altro è da preferire.
Daniel Pryden

1
invece di avere "showException (e)" nella cattura, stavi chiedendo se avevi invece "lanci e" nella cattura (o non hai affatto la prova / cattura)?
MacGyver

Risposte:


146

Sì, c'è un'enorme differenza: il secondo ingoia l'eccezione (dimostrandolo, è vero), mentre il primo lascerà che si propaghi. ( showExceptionPresumo che questo non lo rilanci.)

Quindi, se chiami il primo metodo e "fai qualcosa" fallisce, il chiamante dovrà gestire l'eccezione. Se chiami il secondo metodo e "fai qualcosa" fallisce, il chiamante non vedrà affatto un'eccezione ... il che generalmente è una cosa negativa, a meno che non showExceptionabbia effettivamente gestito l'eccezione, risolto tutto ciò che era sbagliato e generalmente accertato che calculateAreaha raggiunto il suo scopo.

Sarete in grado di dire questo, perché non è possibile chiamare il primo metodo, senza neanche la cattura Exceptionda soli o dichiarando che il metodo potrebbe gettarlo troppo.


12
Quando dici che "A meno che non abbia gestito veramente l'eccezione", questo è un ottimo punto. Ho solo pensato di aggiungere che catturare "Eccezione" di per sé raramente porta a una "gestione" intelligente dell'eccezione effettiva, motivo per cui le persone consigliano di catturare l'eccezione più specifica possibile.
Bill K

17
+1. Perché Jon Skeet ha bisogno di più reputazione. Oh, e anche la risposta era buona.
Jonathan Spiller

20

Il primo throws Exception, quindi il chiamante deve gestire il file Exception. Il secondo rileva e gestisce Exceptioninternamente, quindi il chiamante non deve eseguire alcuna gestione delle eccezioni.


Quindi, in poche parole, dovrei sempre usare il secondo. Ho ragione? Il primo è in realtà un metodo che viene utilizzato in diversi punti del programma. Ecco perché ho deciso di riunire insieme le istruzioni per un ulteriore utilizzo, ma dopo averlo fatto ora mi rendo conto che T stava facendo un grosso errore ..
carlos

9
No, sono necessari entrambi i modelli. Se il tuo metodo è in grado di gestire l'eccezione, usa il secondo modello, altrimenti usa il primo per avvisare il chiamante.
Andreas Dolk

La versione che usi dipende dalle tue esigenze, sostanzialmente a quale livello hai bisogno per gestire quell'eccezione. Il chiamante deve essere codificato di conseguenza. Se un chiamante stava chiamando la prima versione e si sostituisce la definizione del metodo con la seconda versione, il codice del chiamante sarà costretto a gestire l'eccezione poiché si tratta di un'eccezione controllata.
samitgaur

16

Sì. La versione che dichiara throws Exceptionrichiederà il codice chiamante per gestire l'eccezione, mentre la versione che la gestisce esplicitamente non lo farà.

cioè, semplicemente:

performCalculation();

vs. trasferire l'onere della gestione dell'eccezione al chiamante:

try {
    performCalculation();
catch (Exception e) {
    // handle exception
}

6

Sì, c'è molta differenza tra loro. Nel primo blocco di codice, si passa l'eccezione al codice chiamante. Nel secondo blocco di codice lo gestisci tu stesso. Il metodo corretto dipende interamente da ciò che stai facendo. In alcuni casi, si desidera che il codice gestisca l'eccezione (se un file non viene trovato e si desidera crearlo, ad esempio) ma in altri, si desidera che il codice chiamante gestisca l'eccezione (un file non viene trovato e devono specificarne uno nuovo o crearlo).

Anche in generale, non vuoi catturare un'eccezione generica. Invece, ti consigliamo di catturarne solo quelli specifici, come FileNotFoundExceptiono IOExceptionperché possono significare cose diverse.


3

C'è uno scenario particolare in cui non possiamo usare i lanci, dobbiamo usare try-catch. Esiste una regola "Un metodo sottoposto a override non può generare alcuna eccezione aggiuntiva oltre a quella che la sua classe genitore sta lanciando". Se c'è qualche eccezione extra che dovrebbe essere gestita usando try-catch. Considera questo frammento di codice. C'è una semplice classe base

package trycatchvsthrows;

public class Base {
    public void show()
    {
        System.out.println("hello from base");
    }
}

ed è classe derivata:

package trycatchvsthrows;

public class Derived extends Base {

    @Override
    public void show()   {
        // TODO Auto-generated method stub
        super.show();

        Thread thread= new Thread();
        thread.start();
        try {
            thread.sleep(100);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // thread.sleep(10);
        // here we can not use public void show() throws InterruptedException 
        // not allowed
    }
}

Quando dobbiamo chiamare thread.sleep () siamo costretti a usare try-catch, qui non possiamo usare:

 public void show() throws InterruptedException

perché il metodo sottoposto a override non può generare eccezioni aggiuntive.


Credo che non tutti siano a conoscenza di questo avvertimento. Ben indicato.
ivanleoncz

1

Presumo che con "identico" ti riferisci al comportamento.

Un comportamento di una funzione può essere determinato da:

1) Valore restituito

2) Eccezioni generate

3) Effetti collaterali (cioè modifiche nell'heap, nel file system, ecc.)

In questo caso, il primo metodo propaga qualsiasi eccezione, mentre il secondo non genera alcuna eccezione selezionata e inghiotte anche la maggior parte delle eccezioni non verificate, quindi il comportamento È diverso.

Tuttavia, se garantisci che "fai qualcosa" non genera mai un'eccezione, il comportamento sarebbe identico (sebbene il compilatore richiederà al chiamante di gestire l'eccezione, nella prima versione)

--modificare--

Dal punto di vista della progettazione delle API, i metodi sono completamente diversi nel loro contratto. Inoltre, non è consigliabile lanciare un'eccezione di classe. Prova a lanciare qualcosa di più specifico per consentire al chiamante di gestire meglio l'eccezione.


1

Se hai lanciato un'eccezione, il metodo figlio (che sovrascrive questo) dovrebbe gestire l'eccezione

esempio:

class A{
public void myMethod() throws Exception{
 //do something
}
}

A a=new A();
try{
a.myMethod();
}catch Exception(e){
//handle the exception
}

0

Molte volte si desidera che il chiamante gestisca l'eccezione. Supponiamo che tu abbia il chiamante che chiama un metodo che chiama un altro metodo che chiama un altro metodo, invece di avere ogni metodo che gestisce l'eccezione, puoi semplicemente gestirlo al chiamante. A meno che tu non voglia fare qualcosa in uno dei metodi quando quel metodo fallisce.


0

Il chiamante di questo metodo dovrà catturare questa eccezione o dichiararla per essere rilanciata nella sua firma del metodo.

private void calculateArea() throws Exception {
    // Do something
}

Nell'esempio di blocco try-catch di seguito. Il chiamante di questo metodo non deve preoccuparsi di gestire l'eccezione poiché è già stato curato.

private void calculateArea() {
    try {
        // Do something

    } catch (Exception e) {
        showException(e);
    }
}

0
private void calculateArea() throws Exception {
    ....do something
}

Questo genera l'eccezione, quindi il chiamante è responsabile della gestione di tale eccezione, ma se il chiamante non gestisce l'eccezione, potrebbe essere assegnata a jvm, il che potrebbe causare la chiusura anomala del programma.

Mentre nel secondo caso:

private void calculateArea() {
    try {
        ....do something
    } catch (Exception e) {
        showException(e);
    }
}

Qui l'eccezione è gestita dal chiamato, quindi non c'è possibilità di interruzione anomala del programma.

Try-catch è l'approccio consigliato.

IMO,

  • Genera la parola chiave utilizzata principalmente con le eccezioni verificate per convincere il compilatore ma non garantisce la normale terminazione del programma.

  • Genera una parola chiave delegata al
    chiamante (JVM o un altro metodo) la responsabilità della gestione delle eccezioni .

  • La parola chiave Throws è richiesta solo per le eccezioni verificate, per le eccezioni non controllate non viene utilizzata la parola chiave Throws.

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.