Try-with-resources em Kotlin: como se livrar do finally para sempre

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Por que programadores Java choram quando migram para Kotlin?

\n\n

Imagine: você escreve código em Java, abre um arquivo, lê os dados e depois… esquece de fechá-lo. Dor familiar? Em Java, para isso foi criada a construção try-with-resources, que chama automaticamente o close(). Mas quando os desenvolvedores migram para Kotlin, muitas vezes ficam confusos: "Onde está meu amado try (Resource res = ...)?".

\n\n

Spoiler: em Kotlin não existe try-with-resources como uma construção de linguagem separada. E isso é uma boa notícia. Em vez disso, a linguagem oferece uma solução mais elegante e concisa — a função use. Vamos entender como isso funciona e por que seu código ficará mais limpo.

\n\n

O problema: recursos precisam ser fechados

\n\n

Qualquer recurso externo — arquivo, conexão de rede, banco de dados — requer gerenciamento manual. Se você abrir um FileInputStream e não fechá-lo, o sistema pode "vazar" (vazamento de memória) e o arquivo pode ficar bloqueado para outros processos.

\n\n

Em Java, esse problema é resolvido de duas maneiras:

\n\n
    \n
  • Maneira antiga: bloco finally com chamada explícita a close().
  • \n
  • Maneira nova: try-with-resources (introduzido no Java 7).
  • \n
\n\n

Kotlin foi além: ele usa funções de extensão e lambdas para tornar o código não apenas seguro, mas também bonito.

\n\n

Como é o try-with-resources em Java?

\n\n

Para comparação, vejamos o código Java clássico:

\n\n
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {\n    String line = br.readLine();\n    System.out.println(line);\n} catch (IOException e) {\n    e.printStackTrace();\n}\n// br é fechado automaticamente\n
\n\n

Tudo bem, mas há nuances:

\n
    \n
  • É necessário declarar a variável dentro dos parênteses do try.
  • \n
  • Suporta apenas classes que implementam AutoCloseable.
  • \n
  • O código fica volumoso se houver vários recursos.
  • \n
\n\n

Abordagem Kotlin: a função use

\n\n

Em Kotlin, para trabalhar com recursos de forma segura, usa-se a função use. Ela é definida como uma extensão para a interface Closeable (e AutoCloseable para compatibilidade com Java).

\n\n

Veja como fica o mesmo exemplo em Kotlin:

\n\n
import java.io.BufferedReader\nimport java.io.FileReader\n\nfun main() {\n    BufferedReader(FileReader("file.txt")).use { reader ->\n        val line = reader.readLine()\n        println(line)\n    }\n    // reader é fechado automaticamente\n}\n
\n\n

Limpo, conciso, sem try-catch desnecessário? Não exatamente. O use por si só não captura exceções. Ele apenas garante a chamada de close() ao final do bloco. Se precisar tratar um erro, adicione um try-catch externo:

\n\n
try {\n    BufferedReader(FileReader("file.txt")).use { reader ->\n        val line = reader.readLine()\n        println(line)\n    }\n} catch (e: IOException) {\n    println("Erro ao ler o arquivo: ${e.message}")\n}\n
\n\n

Como o use funciona por baixo dos panos?

\n\n

Para entender a mágica, vamos dar uma olhada no código-fonte do Kotlin. A função use é definida na biblioteca padrão mais ou menos assim:

\n\n
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {\n    var exception: Throwable? = null\n    try {\n        return block(this)\n    } catch (e: Throwable) {\n        exception = e\n        throw e\n    } finally {\n        when {\n            exception == null -> close()\n            else -> try {\n                close()\n            } catch (closeException: Throwable) {\n                // suprime a exceção, adiciona-a à exceção principal\n                exception.addSuppressed(closeExcep                

Blogs

Book Recommendations