Quelle est la bonne façon de fermer silencieusement InputStream dans enfin bloquer sans perdre l'exception d'origine?

je me demande si le code ci-dessous ferme InputStream dans enfin bloquer correctement

InputStream is = new FileInputStream("test");
try {
    for(;;) {
        int b = is.read();
        ...
    }
} finally {
    try {
        is.close();
    } catch(IOException e) {
    }
}

si une exception se produit pendant is.read () sera ignoré / supprimé si une exception se produit pendant is.fermer()?

24
demandé sur Evgeniy Dorofeev 2013-04-23 12:01:30
la source

9 ответов

L'exception de l'est.close () sera supprimé et l'exception de is.read () sera celui qui se propage vers le haut.

1
répondu monkjack 2013-04-23 12:04:56
la source

la meilleure façon est D'utiliser Java 7 et d'utiliser try avec les ressources, ou faire la même chose manuellement et ajouter l'exception de fermeture que l'exception supprimée.

Pré Java 7: Si vous lancez votre exception personnalisée, vous pouvez y ajouter l'exception supprimée comme cela est fait dans Java 7 (dans votre liste d'exception créer des champs supprimés et mettre là des exceptions de l'opération de fermeture et quand traiter votre exception, regardez là aussi. Si tu ne peux pas faire ça, Je ne sais pas quoi faire de mieux que de lire il.

exemples: à partir de tutoriels Java

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

mais la meilleure forme est:

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

de cette façon même si la création de FileReader est réussie mais que la création de BufferedReader échoue (par ex. pas assez de mémoire), FileReader sera fermé.

16
répondu Alpedar 2013-04-23 19:30:40
la source

Java 6 spécifications

si l'exécution du bloc d'essai se termine abruptement pour toute autre raison R, alors le bloc final est exécuté. Alors il y a un choix: Si le bloc final se termine normalement, alors la déclaration d'essai se termine abruptement pour la raison R. Si le bloc final se termine abruptement pour des raisons S, alors la déclaration d'essai se termine abruptement pour des raisons S (et la raison R est écartée).

Vous avez donc raison, vous perdrez l'exception d'origine.

la solution est probablement d'écrire votre bloc final de manière défensive qu'il soit une plus grande surprise (qui vaut la peine de se propager) si le bloc final échoue que si une exception sort du bloc try catch.

ainsi, par exemple, s'il est possible que le flux soit nul lorsque vous essayez de le fermer, Vérifiez:

InputStream is = new FileInputStream("test");
try {
    for(;;) {
        int b = is.read();
        ...
    }
} finally {
    try {
        if( is!=null ) {
            is.close();
        }
    } catch(IOException e) {
    }
}

en Java 7, la solution D'Alpedar est la voie à suivre bien sûr.

6
répondu flup 2013-04-24 01:58:56
la source

Vous pouvez le fermer avec IOUtils de https://commons.apache.org/proper/commons-io/

    public void readStream(InputStream ins) {

    try {
        //do some operation with stream         
    } catch (Exception ex) {
        ex.printStackTrace();           
    } finally {
        IOUtils.closeQuietly(ins);
    }       
}
5
répondu Igor Vuković 2015-12-23 10:25:04
la source

Avec le code que vous avez posté:

  • Si is.close() lance IOException, il est écarté et l'exception originale se propage.
  • Si is.close() lance autre chose (a RuntimeException ou un Error), il se propage et l'exception originale est écartée.

avec Java 7, la bonne façon de fermer une entrée sans perdre l'exception d'origine est d'utiliser un try-with-resources déclaration:

try (InputStream is = new FileInputStream("test")) {
    for(;;) {
        int b = is.read();
        // ...
    }
}

Avant pour Java 7, ce que vous faites est très bien, sauf que vous pouvez vouloir attraper toutes les exceptions au lieu de juste IOException.

2
répondu Etienne Miret 2013-04-23 13:37:19
la source

basé sur votre exemple de code si une exception se produit à la int b = is.read(); point, alors, l'exception sera soulevée plus haut dans la chaîne d'appel.

notez cependant que le bloc final s'exécutera toujours et si le Inputstream invalide une autre exception sera levée, mais cette exception s'être "avalé", qui peut être acceptable selon votre cas d'utilisation.

Edit:

D'après le titre de votre question, j'ajouterais que ce que vous avez est très bien à mon avis. Vous pouvez en outre ajouter un catch bloquer pour traiter explicitement (ou peut-être envelopper) n'importe quelle exception dans le premier try block, mais il est également acceptable de laisser les exceptions IO s'élever - cela dépend vraiment de votre API. Il peut être acceptable ou non de laisser les exceptions aux Oi se manifester. Si c'est le cas, alors ce que vous avez bien - si ce n'est pas le cas, vous pourriez vouloir gérer/envelopper L'exception IO avec quelque chose de plus approprié à votre programme.

1
répondu Sean Landsman 2013-04-23 13:33:30
la source

Que Diriez-vous de la prochaine solution:

InputStream is = new FileInputStream("test");
Exception foundException=null;
try {
    for(;;) {
        int b = is.read();
        ...
    }
} catch (Exception e){
  foundException=e;
}
finally {
    if(is!=null)
    try {
        is.close();
    } catch(IOException e) {
    }
}
//handle foundException here if needed
0
répondu android developer 2013-04-23 13:48:36
la source

si une exception se produit pendant is.read () sera ignoré / supprimé si une exception se produit pendant is.fermer()?

Oui. Vous avez un bloc catch pour l'exception dans close () qui ne renvoie pas l'exception. Par conséquent, il n'est pas propagé ou repensé.

0
répondu user207421 2013-04-23 14:56:02
la source

C'est l'exemple pour aider à comprendre votre problème, si vous déclarez le scanner dans le bloc try-catch, il donnera un avertissement au compilateur que la ressource n'est pas fermée. donc, soit le faire localement ou tout simplement à essayer()

import java.util.InputMismatchException;
import java.util.Scanner;

class ScanInt {
public static void main(String[] args) {
    System.out.println("Type an integer in the console: ");

    try (Scanner consoleScanner = new Scanner(System.in);) {
        System.out.println("You typed the integer value: "
                + consoleScanner.nextInt());

    } catch (InputMismatchException | ArrayIndexOutOfBoundsException exception) {
        System.out.println("Catch Bowled");
        exception.printStackTrace();

    }
    System.out.println("----------------");
}
}
0
répondu Dhiraj Himani 2014-12-11 20:31:17
la source

Autres questions sur