Solucionado (ver solução)
Solucionado
(ver solução)
3
respostas

Sobre o try-with-resources - java.io

Olá, estou procurando entender um pouco mais sobre o try-with-resources e no exercício 1 eu tentei utilizá-lo na minha solução. Aparentemente deu certo e ela funciona, mas eu gostaria de compartilhar com vocês o código para ver se a forma como eu fiz é de fato a ideal ou se existe uma forma mais elegante de se fazer. Pra ser sincero eu ainda não peguei o conceito totalmente. Desde já agradeço pelas respostas.

public static void main(String[] args) throws IOException {
        InputStream is = System.in;
        InputStreamReader isr = new InputStreamReader(is);

        try (BufferedReader br = new BufferedReader(isr)) {
            OutputStream os = new FileOutputStream("saida.txt");
            OutputStreamWriter osw = new OutputStreamWriter(os);

            try (BufferedWriter bw = new BufferedWriter(osw)) {
                String linha = br.readLine();

                while (linha != null) {
                    if(linha.equals("exit")) {
                        break;
                    }

                    bw.append(linha);
                    bw.newLine();

                    linha = br.readLine();
                }
            }
        }
    }
3 respostas
solução!

Tudo bem, Fábio?

Quando lidamos com recursos, como acesso ao banco de dados ou leitura de arquivos, é comum que após finalizarmos as operações que temos para fazer, a conexão ou o fluxo sejam encerrados para que o recurso seja liberado.

Para fazer isto, normalmente existe um método chamado close().

Então logo após ler ou escrever em um arquivo, por exemplo, você pode chamar o método close() para liberar o recurso.

Um problema que pode acontecer aí, é que algo pode dar errado no meio do caminho, uma exception pode ocorrer. Então se você põe a chamada do close() dentro de um bloco try:

try {

    InputStream is = new FileInputStream("teste.txt");
    InputStreamReader isr = new InputStreamReader(is);
    BufferedReader br = new BufferedReader(isr);

    String linha = br.readLine();
    System.out.println(linha);

    br.close();

} catch (IOException e) {
    e.printStackTrace();
}

Se uma exception for lançado no meio do caminho, pode ser que o fluxo vá para o catch, e a linha do close() nunca seja executada. A consequência, é que pode ser o recurso fique aberto...

Para garantir que o recurso seja fechado, é comum que o pessoal faça a chamada ao método close() dentro do bloco finally, que é um bloco que temos certeza que será executado independente de haver exception ou não, independente de ele entrar ou não no catch.

Ficaria assim (meio feioso):

BufferedReader br = null;
try {

    InputStream is = new FileInputStream("teste.txt");
    InputStreamReader isr = new InputStreamReader(is);
    br = new BufferedReader(isr);

    String linha = br.readLine();
    System.out.println(linha);

    br.close();

} catch (IOException e) {
    e.printStackTrace();
}
finally {
    try {
        br.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

É aí que entra o try-with-resources. Tudo que você põe nos parenteses dele, o método close() será chamado automaticamente. Para garantir que todo mundo que você por entre parênteses terá o método close(), ele só aceita tipos que implementam a interface AutoClosable. Dessa forma você consegue evitar ter que chamar o close() manualmente.


No seu código, para tratar todas as exceções, você pode por todo mundo dentro do try-with-resources, já que todas essas classes que lidam com arquivos possuem o método close(). Ficaria algo como:

try(InputStream is = System.in;
    InputStreamReader isr = new InputStreamReader(is);
    BufferedReader br = new BufferedReader(isr);

    OutputStream os = new FileOutputStream("saida.txt");
    OutputStreamWriter osw = new OutputStreamWriter(os);
    BufferedWriter bw = new BufferedWriter(osw)) {

    String linha = br.readLine();
    while(linha != null) {
        if(linha.equals("exit")) {
            break;
        }

        bw.append(linha);
        bw.newLine();

        linha = br.readLine();
    }


} catch (IOException e) {
    e.printStackTrace();
}

Na prática, só chamar os métodos close() do BufferedReader e do BufferedWriter é suficiente. Mas como você precisa do InputStreamReader que por sua vez precisa do InputStream, por exemplo, vai ser preciso criar todo mundo dentro do try-with-resources...

Mas agora você garante que o método close() será sempre chamado e o recurso liberado.

Faz sentido? Abraço!

Ah, daria pra fazer assim:

try(BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
     BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("saida.txt")))) {

    // ...
}

Talvez perca um pouco a legibilidade do código... Abraço!

Realmente, eu tentei implementar essa segunda opção e não gostei muito por causa da legibilidade.

Obrigado pela resposta, fez sentido pra mim sim.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software