2009-07-22 3 views
17

Mise à jour: Comme l'indique @PaulGroke ci-dessous, les choses ont changé avec Java 7: il y a maintenant AutoCloseable. Ce qui n'est pas lié aux flux et supporté par la nouvelle construction try-with-resources.Doit-on utiliser Closeable comme équivalent Java pour l'IDisposable de .NET?

AutoCloseable est l'équivalent Java direct de l'interface IDisposable de .NET.


L'interface Closeable introduite dans Java 1.5 est étroitement liée à des flux, et a même un spécificateur d'exception pour IOException. Cela suggère qu'il ne devrait être utilisé que pour des flux ou d'autres activités liées aux opérations d'information, plutôt que pour une logique de nettoyage générale.

Certes, la description de la méthode close() ferait absolument aucun sens en dehors d'un contexte flux/IO:

void close() throws IOException

ce flux et Closes libère toutes les ressources système qui lui sont associés.

Dois-je déclarer donc ma propre interface, Disposable, avec une méthode Dispose() sur elle, et l'utiliser comme un analogue à l'interface de .NET IDisposable? Ou devrais-je réutiliser Closeable même si ce n'est pas un ajustement parfait?

+1

@Pharap Il existe deux modèles distincts pour implémenter 'IDisposable' mentionnés sur la page à laquelle vous liez. L'implémentation de 'Object.Finalize()' n'est requise que dans le scénario relativement rare où votre objet est directement responsable de l'allocation de ressources non gérées (c'est-à-dire des ressources natives qui ne sont pas encapsulées avec un SafeHandle). Votre affirmation que "la méthode recommandée par .NET pour implémenter' IDisposable "[...] nécessite l'utilisation de' Object.Finalize() '" n'est pas tout à fait correcte. –

Répondre

11

D'autant que close() déclenche une exception IOException, vous devez alors écrire le code de gestion des exceptions, je vous conseille d'écrire votre propre interface. Cette interface peut alors lancer toutes les exceptions vérifiées qui sont appropriées à l'utilisation que vous voulez mettre l'interface. Les interfaces ont tendance à signifier l'intention dans l'esprit du lecteur, de sorte qu'une classe mettant en œuvre une interface de fermeture associée à l'E/S fera supposer au lecteur que la classe est également basée sur l'E/S.

Évidemment, si les objets que vous voulez fermer sont tous liés à IO, vous devez utiliser Closeable. Mais sinon aller pour

/** Interface for objects that require cleanup post-use. Call dispose() in finally block! */ 
public interface Disposable { 
    public void dispose(); 
} 
34

Je suis sûr que la plupart des gens sont au courant, mais étant donné que cette question est toujours parmi les meilleurs résultats lors de la recherche « IDisposable Java » (résultat # 2 pour moi tout à l'heure), et ça n'est toujours pas mentionné ici ...

Les choses ont changé avec Java 7: il y a maintenant AutoCloseable. Ce qui n'est pas lié aux flux et supporté par la nouvelle construction try-with-resources.

+0

Bien que je trouve désagréable que Java ait pris tant de temps pour obtenir l'équivalent de 'IDisposable', et j'ai considéré l'absence d'une telle construction comme une faille significative dans Java, je loue les créateurs de Java pour reconnaître la nécessité de permettre à la fois essayez de bloquer les exceptions et les expressions de nettoyage à propager dans la pile des appels. Ma propre préférence aurait été d'avoir 'try-with-resources' pour envelopper toutes les exceptions qui se produisent dans le bloc de nettoyage dans une exception' CleanupFailedException' (qui indiquerait quelle exception - le cas échéant - s'est produite dans le bloc 'try', le long avec une liste d'exceptions de nettoyage) ... – supercat

+0

... et fournir un moyen par lequel le code de nettoyage pourrait dire si le bloc 'try' avait réussi ou échoué (par exemple, si une exception est levée par le code qui modifie quelque chose gardé par un verrou, le verrou ne devrait souvent pas être libéré ni détenu indéfiniment, mais devrait être invalidé pour que toute tentative en attente ou future d'acquérir le verrou jette immédiatement un 'badLockExitException', ce qui serait utile si un -resources construct pourrait permettre à un objet de verrouillage d'implémenter une telle sémantique automatiquement). – supercat

+1

J'ai tendance à être d'accord, bien que la raison en soit la compatibilité ascendante pour permettre à [Closeable] (http://docs.oracle.com/javase/8/docs/api/java/io/Closeable.html) d'étendre [AutoCloseable] (https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html). Une chose à considérer est que si une exception est levée dans le corps et que le nettoyage lance également une exception, les exceptions à bulles [getSuppressed] (http://docs.oracle.com/javase/8/docs/api/java/lang/ Throwable.html # getSuppressed--) contient l'exception de [close()] (https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html#close--). –

1

Lors de la mise en œuvre Closeable (ou AutoClosable pour cette matière) dans une classe, il est également possible d'omettre juste la throws déclaration:

class X implements Closeable { 
    @Override public void close() /* I don't throw */ { 

    } 
} 

Alors, quand quelqu'un utilise un objet typé qu'ils peuvent appeler close() sans avoir à attraper quoi que ce soit:

void f() { // notice no need for throws because close() doesn't throw 
    X x = new X(); 
    try { 
     // do something 
    } finally { 
     x.close(); 
    } 
} 

Il est également compatible avec rien attendre un Closeable: si cet objet est passé dans un endroit qui gère Closeable, ils déjà anticiper une exception et la gérer correctement, bien que futilement dans ce cas.

Cela inclut les bibliothèques comme Guava Closeables et Java 7 essayer avec-ressources comme Paul Groke suggère:

try (X x = new X()) { 
    // do something 
} 

Il y a une mise en garde rare si vous ne pouvez pas réintroduire l'exception des enfants classes une fois il est dénudé:

class Y extends X { 
            /* compile error */ 
    @Override public void close() throws IOException { 
     // Y.close clashes with X.close: overridden method does not throw IOException 
    } 
}