Est-ce que j'utilise correctement la version d'évaluation de Java 7 avec les ressources

87

Je m'attends à ce que le lecteur tamponné et le lecteur de fichiers se ferment et que les ressources soient libérées si l'exception est lancée.

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{
    try (BufferedReader br = new BufferedReader(new FileReader(filePath)))
    {
        return read(br);
    } 
}

Cependant, est-il nécessaire d'avoir une catchclause pour une clôture réussie?

ÉDITER:

Essentiellement, le code ci-dessus en Java 7 est-il équivalent au code ci-dessous pour Java 6:

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{

    BufferedReader br = null;

    try
    {
        br = new BufferedReader(new FileReader(filePath));

        return read(br);
    }
    catch (Exception ex)
    {
        throw ex;
    }
    finally
    {
        try
        {
            if (br != null) br.close();
        }
        catch(Exception ex)
        {
        }
    }

    return null;
}
guépard
la source
Après avoir relu votre question, je ne sais pas si je la comprends bien. Pouvez-vous l'expliquer?
Maroun
Salut. Cheetah, j'essaie de comprendre le rôle du premier catchde votre exemple pour Java 6. C'est-à-dire catch (Exception ex) { throw ex; }- c'est juste relancer l'exception, ça ne fait rien, ça peut être facilement enlevé sans aucun mal. Ou est-ce que je manque quelque chose?
Sasha le

Réponses:

103

C'est correct et il n'y a aucune exigence d' catcharticle. 7 doc Oracle dit que la ressource sera fermée indépendamment de savoir si une exception est en fait jeté ou non.

Vous ne devez utiliser une catchclause que si vous souhaitez réagir à l'exception. La catchclause sera exécutée après la fermeture de la ressource.

Voici un extrait du tutoriel d' Oracle :

L'exemple suivant lit la première ligne d'un fichier. Il utilise une instance de BufferedReader pour lire les données du fichier. BufferedReader est une ressource qui doit être fermée une fois le programme terminé:

static String readFirstLineFromFile(String path) throws IOException {
    try (BufferedReader br =
                   new BufferedReader(new FileReader(path))) {
        return br.readLine();
    }
} // In this example, the resource declared in the try-with-resources statement is a BufferedReader.

... Étant donné que l'instance de BufferedReader est déclarée dans une instruction try-with-resource, elle sera fermée indépendamment du fait que l'instruction try se termine normalement ou brusquement (suite à la levée d'une IOException par la méthode BufferedReader.readLine).

ÉDITER

Concernant la nouvelle question éditée:

Le code de Java 6 exécute catchle finallybloc et ensuite . Cela provoque l'ouverture potentielle des ressources dans le catchbloc.

Dans la syntaxe Java 7, les ressources sont fermées avant le catchbloc, donc les ressources sont déjà fermées pendant l' catchexécution du bloc. Ceci est documenté dans le lien ci-dessus:

Dans une instruction try-with-resources, tout bloc catch ou finally est exécuté une fois que les ressources déclarées ont été fermées.

yair
la source
69

Votre utilisation de try-with-resources fonctionnera correctement dans ce cas particulier, mais ce n'est pas tout à fait correct en général. Vous ne devez pas enchaîner les ressources de cette manière, car cela peut entraîner des surprises désagréables. Supposons que vous ayez une taille de tampon variable:

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{
    int sz = /* get buffer size somehow */
    try (BufferedReader br = new BufferedReader(new FileReader(filePath), sz))
    {
        return read(br);
    } 
}

Supposons que quelque chose s'est mal passé et que vous ayez fini par szêtre négatif. Dans ce cas, votre ressource de fichier (créée via new FileReader(filePath)) ne sera PAS fermée.

Pour éviter ce problème, vous devez spécifier chaque ressource séparément comme ceci:

public static Object[] fromFile(String filePath) throws FileNotFoundException, IOException
{
    int sz = /* get buffer size somehow */
    try (FileReader file = new FileReader(filePath);
         BufferedReader br = new BufferedReader(file, sz))
    {
        return read(br);
    } 
}

Dans ce cas, même si l'initialisation des bréchecs est filetoujours fermée. Vous pouvez trouver plus de détails ici et ici .

Andrii Polunin
la source
J'essaie de comprendre pourquoi la ressource créée via new FileReader(filePath))ne se ferme pas au cas où un IllegalArgumentExceptionserait jeté lorsque sz est négatif. Le try-with-resources ne ferme-t-il pas toutes les AutoClosableressources indépendamment des exceptions levées?
Prasoon Joshi
3
@PrasoonJoshi Non, il n'appelle .close()que les variables qui ont été déclarées dans l'initialiseur try-with-resources. C'est pourquoi le séparer en deux déclarations dans cet exemple fait l'affaire.
Mario Carneiro le
4
Andrii et @Mario Vous avez à la fois raison et tort. Dans le premier exemple, le FileReader n'est pas fermé par la logique try-with-resource. Mais lorsque le BufferedReader est fermé, il fermera également le FileReader encapsulé. Pour preuve, jetez un œil à la source de java.io.BufferedReader.close (). En conséquence, le code du premier exemple devrait être préféré, car il est plus concis.
jschreiner
7
@jschreiner Vrai, bien que le problème (quelque peu artificiel) d'Andrii dans lequel sz < 0le constructeur lance une exception provoquera en fait une fuite de la ressource.
Mario Carneiro
5
@mario Je suis d'accord. Le constructeur externe pourrait échouer et la ressource interne serait divulguée. Je n'ai pas vu ça avant, merci.
jschreiner