2009-07-22 21 views
17

Actualización: Como señala @PaulGroke a continuación, las cosas han cambiado con Java 7: ahora es AutoCloseable. Que no está vinculado a las secuencias y es compatible con la nueva construcción try-with-resources.¿Debería utilizarse Closeable como equivalente Java para IDisposable de .NET?

AutoCloseable es el equivalente directo de Java para la interfaz IDisposable de .NET.


La interfaz Closeable introducido en Java 1.5 está estrechamente ligada a las corrientes, e incluso tiene un especificador de excepción para IOException. Esto sugiere que solo debe usarse para flujos u otras actividades relacionadas con IO, en lugar de la lógica de limpieza de propósito general.

Ciertamente, la descripción del método close() haría absolutamente ningún sentido fuera de un contexto de secuencia/IO:

void close() throws IOException

Cierra esta corriente y libera los recursos del sistema asociados a ella.

¿Debo declarar, por tanto, mi propia interfaz, Disposable, con un método Dispose() en él, y usar eso como un análogo a la interfaz de .NET IDisposable? ¿O debería volver a usar Closeable aunque no encaje perfectamente?

+1

@Pharap Hay dos patrones separados para implementar 'IDisposable' mencionado en la página que enlaza. La implementación de 'Object.Finalize()' solo es necesaria en el escenario relativamente raro de que su objeto sea directamente responsable de asignar recursos no administrados (es decir, recursos nativos que no están incluidos en un SafeHandle). Su afirmación de que "la forma recomendada de .NET para implementar 'IDisposable' [...] requiere el uso de' Object.Finalize() '" no es del todo correcto. –

Respuesta

11

Especialmente dado que close() arroja una IOException para la que debe escribir el código de manejo de excepciones, le aconsejo que escriba su propia interfaz. Esta interfaz puede arrojar cualquier excepción marcada que sea apropiada para el uso al que desea colocar la interfaz.

Las interfaces tienden a significar intenciones en la mente del lector, por lo que hacer que una clase implemente una interfaz estrechable asociada a IO hará que el lector suponga que la clase también está basada en IO.

Obviamente, si los objetos que desea cerrar son todos relacionados con IO, debe utilizar Cerrar. Pero por lo demás voy para

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

Estoy seguro de que la mayoría de las personas son conscientes de ello, pero ya que esta cuestión es todavía entre los primeros resultados al buscar por "IDisposable Java" (# 2 resultado para mí ahora mismo), y todavía no se menciona aquí ...

Las cosas han cambiado con Java 7: ahora está AutoCloseable. Que no está vinculado a las transmisiones y es compatible con la nueva construcción try-with-resources.

+0

Si bien me resulta molesto que Java haya tardado tanto en obtener el equivalente de 'IDisposable', y consideré la falta de tal construcción como una falla significativa en Java, alaba a los creadores de Java por reconocer la necesidad de permitir ambos las excepciones try-block y de limpieza se propagarán por la pila de llamadas. Mi propia preferencia habría sido tener 'try-with-resources' wrap cualquier excepción que ocurra en el bloque de limpieza en una' CleanupFailedException' (que indicaría qué excepción, si hubo alguna, ocurrió en el bloque 'try', junto con con una lista de excepciones de limpieza) ... – supercat

+0

... y también proporciona un medio por el cual el código de limpieza podría indicar si el bloque 'try' tuvo éxito o falló (por ejemplo, si se produce una excepción por código que está modificando algo guardado por una cerradura, la cerradura a menudo no debe ser liberada ni retenida indefinidamente, sino que debe ser invalidada de modo que cualquier intento pendiente o futuro de adquirir la cerradura arroje una 'badLockExitException' inmediata; sería útil si intentara con la construcción de recursos podría permitir que un objeto de bloqueo implemente dicha semántica automáticamente). – supercat

+1

Tiendo a estar de acuerdo, aunque el motivo es la compatibilidad con versiones anteriores para permitir [Cerrar] (http://docs.oracle.com/javase/8/docs/api/java/io/Closeable.html) extender [AutoCloseable] (https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html). Una cosa a tener en cuenta es que si se lanza una excepción en el cuerpo y la limpieza también arroja una excepción, las excepciones borradas [getSuppressed] (http://docs.oracle.com/javase/8/docs/api/java/lang/ Throwable.html # getSuppressed--) contiene la excepción de [close()] (https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html#close--). –

1

Al implementar Closeable (o AutoClosable para el caso) en una clase también es posible omitir simplemente los tiros declaración:

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

    } 
} 

Así que cuando alguien está utilizando un objeto con tipo que puedan llamar close() sin tener que coger nada:

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

también es compatible con cualquier cosa esperando un Closeable: si este objeto se pasa en alguna parte que se encarga de Closeable, se ya anticipó una excepción y la manejó correctamente, aunque en vano en este caso.

Esto incluye bibliotecas como Guava Closeables y Java 7 try-con-recursos como sugiere Paul Groke:

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

Hay una advertencia rara sin embargo: no se puede reintroducir la excepción en la crianza de clases una vez está despojado:

Cuestiones relacionadas