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!