Domanda

Bene, ho fatto quanto segue (i nomi delle variabili sono stati cambiati):


FileInputStream fis = null;
try
{
    fis = new FileInputStream(file);

    ... process ...

}
catch (IOException e)
{
    ... handle error ...
}
finally
{
    if (fis != null)
        fis.close();
}

Di recente, ho iniziato a utilizzare FindBugs, il che suggerisce che non sto chiudendo correttamente i flussi. Decido di vedere se c'è qualcosa che può essere fatto con un blocco finalmente {}, e poi vedo, oh sì, close () può lanciare IOException. Cosa dovrebbero fare le persone qui? Le librerie Java generano troppe eccezioni verificate.

È stato utile?

Soluzione

Per Java 7 e versioni successive try-with-resources dovrebbe essere usato:

try (InputStream in = new FileInputStream(file)) {
  // TODO: work
} catch (IOException e) {
  // TODO: handle error
}

Se sei bloccato su Java 6 o versioni precedenti ...

Questo schema evita di confonderti con null :

    try {
        InputStream in = new FileInputStream(file);
        try {
            // TODO: work
        } finally {
            in.close();
        }
    } catch (IOException e) {
        // TODO: error handling
    }

Per maggiori dettagli su come gestire efficacemente chiudi , leggi questo post sul blog: Java: come non fare confusione con la gestione dei flussi . Ha più codice di esempio, più profondità e copre le insidie ??del wrapping close in un blocco catch .

Altri suggerimenti

Qualcosa di simile al seguente dovrebbe farlo, a te decidere se lanciare o ingoiare IOException nel tentativo di chiudere lo stream.

FileInputStream fis = null;
try
{
    fis = new FileInputStream(file);

    ... process ...


}
catch (IOException e)
{
    ... blah blah blah ...
}
finally
{
    try
    {
        if (fis != null)
            fis.close();
    }
    catch (IOException e)
    {
    }
}

Puoi utilizzare il try- con risorse aggiunta JDK7. È stato creato proprio per affrontare questo tipo di cose

static String readFirstLineFromFile(String path) throws IOException {
  try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
  }
}

La documentazione dice:

  

L'istruzione try-with-resources assicura che ogni risorsa sia chiusa   alla fine della dichiarazione.

Puoi anche usare un semplice metodo Helper statico:

public static void closeQuietly(InputStream s) {
   if (null == s) {
      return;
   }
   try {
      s.close();
   } catch (IOException ioe) {
      //ignore exception
   }
}

e utilizzalo dal tuo blocco finally.

Non c'è molto altro da aggiungere, tranne un suggerimento stilistico molto minore. L'esempio canonico del codice di auto-documentazione si applica in questo caso: dai un nome di variabile descrittivo al IOException ignorato che devi catturare su close () .

Quindi la risposta di Squiddle diventa:

public static void closeQuietly(InputStream s) {
   try {
      s.close();
   } catch (IOException ignored) {
   }
}

Nella maggior parte dei casi, trovo che sia meglio non catturare le eccezioni di I / O e utilizzare semplicemente try-finally:

final InputStream is = ... // (assuming some construction that can't return null)
try {
    // process is
    ...
} finally {
    is.close();
}

Ad eccezione di FileNotFoundException , generalmente non puoi " aggirare " un IOException . L'unica cosa che resta da fare è segnalare un errore e in genere lo gestirai più in alto nello stack di chiamate, quindi trovo meglio propagare l'eccezione.

Poiché IOException è un'eccezione verificata, dovrai dichiarare che questo codice (e tutti i suoi client) genera IOException . Potrebbe essere troppo rumoroso o potresti non voler rivelare i dettagli di implementazione dell'utilizzo di IO. In tal caso, puoi racchiudere l'intero blocco con un gestore di eccezioni che racchiude IOException in un RuntimeException o in un tipo di eccezione astratto.

Dettaglio: Sono consapevole che il codice sopra riportato ingoia qualsiasi eccezione dal blocco try quando l'operazione chiudi nel finalmente produce un IOException . Non penso che sia un grosso problema: in genere, l'eccezione dal blocco try sarà lo stesso IOException che causa la chiusura di fail (cioè è abbastanza raro che IO funzioni bene e poi fallisca nel punto di chiusura). Se questa è una preoccupazione, potrebbe valere la pena di "mettere a tacere" la chiusura.

La seguente soluzione genera correttamente un'eccezione se la chiusura fallisce senza nascondere una possibile eccezione prima della chiusura.

try {
    InputStream in = new FileInputStream(file);
    try {
        // work
        in.close();
    } finally {
        Closeables.closeQuietly(in);
    }
} catch(IOException exc) {
    // kernel panic
}

Questo funziona perché la chiamata si chiude una seconda volta non ha alcun effetto .

Questo si basa sulla guava Closeables , ma si può scrivere il proprio metodo closeQuietly se si preferisce, come mostrato da squiddle (vedi anche serg10 ).

La segnalazione di un errore di chiusura, nel caso generale, è importante perché close potrebbe scrivere alcuni byte finali nello stream, ad es. a causa del buffering. Quindi, il tuo utente vuole sapere se ha fallito o probabilmente vuoi agire in qualche modo. Certo, questo potrebbe non essere vero nel caso specifico di un FileInputStream, non lo so (ma per motivi già menzionati penso che sia meglio segnalare un errore ravvicinato se si verifica comunque).

Il codice sopra è un po 'difficile da comprendere a causa della struttura dei blocchi di prova incorporati. Potrebbe essere considerato più chiaro con due metodi, uno che genera un'eccezione IOEx e uno che la cattura. Almeno questo è ciò che opterei per.

private void work() throws IOException {
    InputStream in = new FileInputStream(file);
    try {
        // work
        in.close();
    } finally {
        Closeables.closeQuietly(in);
    }
}

public void workAndDealWithException() {
    try {
        work();
    } catch(IOException exc) {
        // kernel panic
    }
}

Basato su http : //illegalargumentexception.blogspot.com/2008/10/java-how-not-to-make-mess-of-stream.html (a cui fa riferimento McDowell).

Speriamo di avere delle chiusure in Java un giorno e poi perderemo molta verbosità.

Quindi, invece, ci sarà un metodo di supporto da qualche parte in javaIO che puoi importare, probabilmente ci vorrà un " Chiudibile " interfaccia e anche un blocco. All'interno di quel metodo helper, try {closable.close ()} catch (IOException ex) {// blah} è definito una volta per tutte, e quindi sarai in grado di scrivere

 Inputstream s = ....;
 withClosable(s) {
    //your code here
 }

Ti preoccupi principalmente di ottenere un rapporto pulito da FindBugs o di avere un codice che funzioni? Queste non sono necessariamente la stessa cosa. Il tuo codice originale va bene (anche se mi sbarazzerei del ridondante se (fis! = Null) controlla poiché un OutOfMemoryException sarebbe stato lanciato altrimenti). FileInputStream ha un metodo finalizzatore che chiuderà il flusso per te nel caso improbabile che tu riceva effettivamente una IOException durante l'elaborazione. Semplicemente non vale la pena preoccuparsi di rendere il tuo codice più sofisticato per evitare lo scenario estremamente improbabile di

  1. ottieni una IOException e
  2. questo accade così spesso che inizi a incorrere in problemi di backlog del finalizzatore.

Modifica: se ricevi così tante IOExceptions che stai riscontrando problemi con la coda del finalizzatore, allora hai pesci molto più grandi da friggere! Si tratta di ottenere un senso della prospettiva.

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