2010-06-16 3 views
21

Sto usando uno scrittore bufferizzato e il mio codice, chiude lo scrittore nel blocco finally. Il mio codice è come questoVa bene usare try catch inside, infine?

........... 
    BufferedWriter theBufferedWriter = null; 
    try{ 
    theBufferedWriter =..... 
    .... 
    ...... 
    ..... 
    } catch (IOException anException) { 
    .... 
    } finally { 
     try { 
      theBufferedWriter.close();    
     } catch (IOException anException) { 
      anException.printStackTrace(); 
      } 
    } 

devo usare il tentativo di cattura all'interno del codice pulito nel infine come theBufferedWriter potrebbe anche lanciare un'IOException. Non voglio lanciare questa eccezione al methos chiamante. È una buona pratica usare finalmente un try catch? Se no, qual è l'alternativa? Si prega di suggerire.

saluti, Hiral

+1

ok, ma per verificare null prima è meglio. – qrtt1

+0

+1 Non è bello ma deve essere fatto –

risposta

14

Un modo un po 'più bello per farlo è quello di utilizzare IOUtils.closeQuiety da Apache commons-io. Mantiene il tuo codice in ordine ed elimina parte del boilerplate inerente a Java.

codice Si diventa allora:

BufferedWriter theBufferedWriter = null; 
try{ 
    theBufferedWriter = ... 
    ... 
} catch (IOException anException) { 
    ... 
} finally { 
    IOUtils.closeQuietly(theBufferedWriter); 
} 

molto più bello e più espressivo.

+3

Chiudere un scrittore buffered come questo è rischioso; se i caratteri rimangono nel buffer e close genera un'eccezione quando provano a scriverli, i dati vengono troncati e l'applicazione non gestisce l'errore. Per renderlo sicuro, devi chiamare 'close' appena prima del blocco catch. – McDowell

+2

@ McDowell: Buono a sapersi. Presumibilmente si potrebbe chiamare 'flush()' anche prima del blocco catch, giusto? –

+2

chiudendo il buffer lo svuoterà (vedi javadoc). _ Nel caso in cui non sia chiaro, questo modello richiede che 'close' venga chiamato due volte. Se spostassi lo stato _try/finally {close} _ nel blocco _try_ esistente, avresti 1) solo bisogno di chiamare' close' una volta 2) evitare l'assegnazione 'null' ridondante 3) non è necessario importare una libreria di terze parti. Le trame nidificate appaiono brutte, ma di solito non puoi prendere decisioni in merito alla gestione degli errori a livello locale, quindi il blocco catch si troverà in un chiamante più in alto nello stack delle chiamate. http://illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of-stream.html – McDowell

11

Nel pre Java 7, direi che ciò che avete scritto è la soluzione migliore.

In Java 7 e in avanti è necessario Automatic Resource Management per semplificare queste operazioni. Grazie a questa funzione, si può fare

BufferedWriter theBufferedWriter = null; 
try (BufferedWriter theBufferedWriter = ...) { 
.... 
...... 
..... 
} catch (IOException anException) { 
.... 
} 
+0

Sono d'accordo provare con la risorsa è l'approccio migliore da Java 7: https://docs.oracle.com/javase/tutorial/essential/exceptions/tryResourceClose.html – JavaDev

1

Questo è ciò con cui dovremo convivere fino a Java 7 e ARM Blocks.

2

Oppure è possibile utilizzare Lombok e l'annotazione @Cleanup e non si dovrà mai scrivere un tentativo di cattura all'interno finalmente di nuovo.

Ecco come si farebbe normalmente scriverlo (noti la throws IOException):

//Vanilly Java 

import java.io.*; 

public class CleanupExample { 
    public static void main(String[] args) throws IOException { 
    InputStream in = new FileInputStream(args[0]); 
    try { 
     OutputStream out = new FileOutputStream(args[1]); 
     try { 
     byte[] b = new byte[10000]; 
     while (true) { 
      int r = in.read(b); 
      if (r == -1) break; 
      out.write(b, 0, r); 
     } 
     } finally { 
     out.close(); 
     } 
    } finally { 
     in.close(); 
    } 
    } 
} 

Ora con Lombok basta scrivere @Cleanup sui flussi

import lombok.Cleanup; 
import java.io.*; 

public class CleanupExample { 
    public static void main(String[] args) throws IOException { 
    @Cleanup InputStream in = new FileInputStream(args[0]); 
    @Cleanup OutputStream out = new FileOutputStream(args[1]); 
    byte[] b = new byte[10000]; 
    while (true) { 
     int r = in.read(b); 
     if (r == -1) break; 
     out.write(b, 0, r); 
    } 
    } 
} 
1

E 'OK, ma si dovrebbe verificare se theBufferedWriter non è nullo prima di chiuderlo.
Si potrebbe anche fare:

BufferedWriter theBufferedWriter; 
try { 
    theBufferedWriter = new ... 
    try { 
     ... 
    } finally { 
     try { 
      theBufferedWriter.close(); 
     } catch (IOException closeException) { 
      closeException.printStackTrace(); 
     } 
    } 
} catch (IOException anException) { 
    ... 
} 

o:

BufferedWriter theBufferedWriter; 
try { 
    theBufferedWriter = new ... 
} catch (IOException createException) { 
    // do something with createException 
    return; // assuming we are in a method returning void 
} 

try { 
    ... 
} catch (IOException anException) { 
    ... 
    // assuming we don't return here 
} 

try { 
    theBufferedWriter.close(); 
} catch (IOException closeException) { 
    closeException.printStackTrace(); 
} 

ma soprattutto mi fare queste operazioni (ad esempio, la scrittura di un file) in un metodo dedicato e preferiscono gettare il/un'eccezione in modo che il chiamante in grado di gestire (ad esempio, chiedono un altro file, arrestare l'applicazione, ...):

void someMethod(...) throws IOException { 
    BufferedWriter theBufferedWriter = new ... 

    try { 
     ... 
    } catch (IOExcepption anException) { 
     try { 
      theBufferedWriter.close(); 
     } catch (IOException closeException) { 
      closeException.printStackTrace(); 
      // closeException is not thrown, anException represents the main/first problem 
     } 
     throw anException; 
    } 

    theBufferedWriter.close(); // throws the Exception, if any 
} 

si prega di notare: l'inglese non è la mia abeti t né la mia seconda lingua, qualsiasi aiuto sarebbe apprezzato

0

È ok per mettere un try-catch in un finalmente. È lo strumento che fa ciò che vuoi fare. Tuttavia, ritengo che la IOException generata alla chiusura sia abbastanza rara da consentirmi di sopprimere qualsiasi eccezione nel corpo in questo modo.

try { 
    BufferedWriter writer = ..... 
    try { 
     ..... 
    } finally { 
     writer.close(); 
    } 
} catch (IOException e) { 
    .... 
}