¿Estoy usando los recursos de prueba de Java 7 correctamente?

87

Espero que el lector de búfer y el lector de archivos se cierren y los recursos se liberen si se lanza la excepción.

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

Sin embargo, ¿existe algún requisito para tener una catchcláusula para un cierre exitoso?

EDITAR:

Esencialmente, el código anterior en Java 7 es equivalente al siguiente para 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;
}
leopardo
fuente
Después de leer su pregunta nuevamente, no estoy seguro de haberla entendido bien. ¿Puedes explicarlo?
Maroun
Hola. Cheetah, estoy tratando de entender el papel del primero catchde tu ejemplo para Java 6. Es decir catch (Exception ex) { throw ex; }, simplemente está volviendo a lanzar la excepción, no hace nada, se puede eliminar fácilmente sin ningún daño. ¿O me estoy perdiendo algo?
Sasha

Respuestas:

103

Es correcto y no hay requisito de catchcláusula. Oracle java 7 doc dice que el recurso se cerrará independientemente de si se lanza una excepción o no.

Debe usar una catchcláusula solo si desea reaccionar ante la excepción. La catchcláusula se ejecutará después de que se cierre el recurso.

Aquí hay un fragmento del tutorial de Oracle :

El siguiente ejemplo lee la primera línea de un archivo. Utiliza una instancia de BufferedReader para leer datos del archivo. BufferedReader es un recurso que debe cerrarse después de que el programa haya terminado con él:

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.

... Debido a que la instancia de BufferedReader se declara en una declaración try-with-resource, se cerrará independientemente de si la declaración try se completa de forma normal o abrupta (como resultado del método BufferedReader.readLine arrojando una IOException).

EDITAR

Con respecto a la nueva pregunta editada:

El código en Java 6 ejecuta el catchy luego el finallybloque. Esto hace que los recursos todavía estén potencialmente abiertos en el catchbloque.

En la sintaxis de Java 7, los recursos se cierran antes del catchbloque, por lo que los recursos ya están cerrados durante la catchejecución del bloque. Esto está documentado en el enlace anterior:

En una declaración try-with-resources, cualquier catch o finalmente bloque se ejecuta después de que se hayan cerrado los recursos declarados.

yair
fuente
69

El uso de try-with-resources funcionará bien en este caso particular, pero no es del todo correcto en general. No debe encadenar recursos como ese porque puede llevar a sorpresas desagradables. Suponga que tiene un tamaño de búfer 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);
    } 
}

Suponga que algo salió mal y terminó szsiendo negativo. En este caso, su recurso de archivo (creado mediante new FileReader(filePath)) NO se cerrará.

Para evitar este problema, debe especificar cada recurso por separado de esta manera:

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);
    } 
}

En este caso, incluso si la inicialización de brfallas filetodavía se cierra. Puede encontrar más detalles aquí y aquí .

Andrii Polunin
fuente
Estoy tratando de entender por qué el recurso creado a través de new FileReader(filePath))no se cerraría en caso de que IllegalArgumentExceptionse lanzara un cuando sz es negativo. ¿No cierra el try-with-resources todos los AutoClosablerecursos independientemente de las excepciones lanzadas?
Prasoon Joshi
3
@PrasoonJoshi No, solo llama .close()a las variables que se han declarado en el inicializador try-with-resources. Es por eso que separarlo en dos declaraciones en este ejemplo funciona.
Mario Carneiro
4
Andrii y @Mario Tienen razón y están equivocados. En el primer ejemplo, FileReader no se cierra mediante la lógica de prueba con recursos. Pero cuando el BufferedReader está cerrado, también cerrará el FileReader empaquetado. Como prueba, eche un vistazo a la fuente de java.io.BufferedReader.close (). Como consecuencia, se debe preferir el código del primer ejemplo, porque es más conciso.
jschreiner
7
@jschreiner Verdadero, aunque el problema de Andrii (algo artificial) en el que sz < 0hace que el constructor arroje una excepción de hecho hará que el recurso se filtre.
Mario Carneiro
5
@mario estoy de acuerdo. El constructor externo podría fallar y el recurso interno se filtraría. No vi eso antes, gracias.
jschreiner