Question
In Java, I would normally use a try-with-resources statement to automatically close a resource such as a writer or stream. When I tried to write an equivalent in Kotlin, it did not work.
For example, I tried variations like this:
try (writer = OutputStreamWriter(r.getOutputStream())) {
// ...
}
However, Kotlin does not accept this syntax. Is there a Kotlin equivalent to Java's try-with-resources?
I also noticed that Kotlin's grammar for a try block is defined like this:
try : "try" block catchBlock* finallyBlock?;
So it seems Kotlin does not include Java-style try-with-resources syntax directly. What should be used instead?
Short Answer
By the end of this page, you will understand why Kotlin does not support Java-style try (...) {} syntax, and how to achieve the same result using Kotlin's use() function. You will also learn when resources are closed, how exceptions behave, and how this pattern is used in real Kotlin code.
Concept
Kotlin does not have a special language construct that matches Java's try-with-resources syntax.
In Java, this is valid:
try (BufferedReader reader = new BufferedReader(...)) {
// use reader
}
That syntax is part of the Java language itself.
In Kotlin, the equivalent idea is usually handled with the use() extension function. Instead of adding resource management to the try syntax, Kotlin provides a standard library function that:
- works with a closable resource
- runs a block of code with that resource
- automatically closes the resource when the block finishes
- still closes the resource if an exception happens
Typical Kotlin style looks like this:
OutputStreamWriter(r.getOutputStream()).use { writer ->
writer.write("Hello")
}
This matters because resource management is a common programming task. Files, sockets, database streams, readers, and writers all need to be closed reliably. Forgetting to close them can cause:
- memory pressure
- file descriptor leaks
- locked files
- network connection issues
- hard-to-debug production errors
So even though Kotlin does not copy Java's syntax, it still gives you a safe and idiomatic way to handle resources.
Mental Model
Think of a resource like borrowing a tool from a workshop.
- You borrow the tool: open a file, create a stream, get a writer.
- You use it for a task.
- You must return it when finished.
Java says: "Borrow the tool inside the try (...) header, and Java will return it for you."
Kotlin says: "Take the tool, call use { ... }, do your work inside the block, and Kotlin will return it for you afterward."
So use() is like a supervised borrowing process:
- open resource
- do work inside the block
- close resource automatically
- even if something goes wrong, still close it
Syntax and Examples
The basic Kotlin syntax is:
resource.use { value ->
// work with value
}
For a writer, that becomes:
val output = r.getOutputStream()
OutputStreamWriter(output).use { writer ->
writer.write("Hello, Kotlin")
}
You can also chain resource creation directly:
OutputStreamWriter(r.getOutputStream()).use { writer ->
writer.write("Hello")
writer.flush()
}
Reading from a file
java.io.File("data.txt").bufferedReader().use { reader ->
val text = reader.readLine()
println(text)
}
Writing to a file
java.io.File("log.txt").bufferedWriter().use { writer ->
writer.write("Application started")
}
Why this works
use() executes the lambda block and closes the resource afterward. This gives Kotlin the same practical benefit as Java's try-with-resources, but with a library function instead of special syntax.
Step by Step Execution
Consider this example:
java.io.File("notes.txt").bufferedWriter().use { writer ->
writer.write("Line 1")
}
println("Done")
Here is what happens step by step:
java.io.File("notes.txt")creates aFileobject..bufferedWriter()opens a writer for that file..use { writer -> ... }starts a managed block.- Inside the block,
writer.write("Line 1")writes text to the file. - The block ends.
- Kotlin automatically closes
writer. println("Done")runs after the resource has already been closed.
If an exception happens
java.io.File("notes.txt").bufferedWriter().use { writer ->
writer.write("Before error")
error("Something failed")
}
Execution flow:
- The writer is opened.
"Before error"is written.error(...)throws an exception.
Real World Use Cases
Resource management appears in many common programming tasks.
File handling
java.io.File("report.txt").inputStream().use { input ->
val bytes = input.readBytes()
println(bytes.size)
}
Used for:
- reading config files
- writing logs
- exporting reports
Network I/O
val connection = java.net.URL("https://example.com").openConnection()
connection.getInputStream().use { input ->
val text = input.bufferedReader().readText()
println(text)
}
Used for:
- API calls
- downloading content
- reading remote data streams
Working with sockets
Resources such as socket streams must be closed even if requests fail.
Database and storage APIs
Some APIs expose closable cursors, streams, or readers. use() helps ensure they are always cleaned up.
Android and server apps
Common examples include:
- reading app assets
- handling uploaded files
- streaming HTTP responses
- writing temporary files
Real Codebase Usage
In real Kotlin projects, developers usually combine use() with a few common patterns.
1. Guard clauses before opening resources
fun saveText(path: String?, text: String) {
if (path.isNullOrBlank()) return
java.io.File(path).bufferedWriter().use { writer ->
writer.write(text)
}
}
This avoids opening a resource if input is invalid.
2. try/catch around use()
fun readConfig(path: String): String? {
return try {
java.io.File(path).bufferedReader().use { it.readText() }
} catch (e: java.io.IOException) {
null
}
}
This is common for file and network operations.
3. Nested use() for multiple resources
java.io.FileInputStream("input.txt").use { input ->
java.io.FileOutputStream("output.txt").use { output ->
input.copyTo(output)
}
}
Common Mistakes
Mistake 1: Trying to use Java syntax directly
Broken code:
try (writer = OutputStreamWriter(r.getOutputStream())) {
writer.write("Hello")
}
Why it fails:
- Kotlin does not support Java's
try (...)syntax.
Use this instead:
OutputStreamWriter(r.getOutputStream()).use { writer ->
writer.write("Hello")
}
Mistake 2: Opening a resource and forgetting to close it
Broken code:
val writer = OutputStreamWriter(r.getOutputStream())
writer.write("Hello")
Problem:
- the writer may remain open
- buffered data may not be fully written
Better:
OutputStreamWriter(r.getOutputStream()).use { writer ->
writer.write("Hello")
}
Mistake 3: Using the resource outside the use() block
Broken code:
val writer = OutputStreamWriter(r.getOutputStream())
writer.use {
it.write()
}
writer.write()
Comparisons
| Concept | Java | Kotlin | Notes |
|---|---|---|---|
| Automatic resource closing | try (resource) {} | resource.use {} | Same goal, different syntax |
| Part of language syntax? | Yes | No | Kotlin uses a library function |
| Exception handling | catch / finally | try/catch/finally around use() | Often combined with use() |
| Multiple resources | try (a; b) {} | nested blocks |
Cheat Sheet
// Kotlin equivalent of Java try-with-resources
resource.use { value ->
// use value
}
Key rules
- Kotlin does not support
try (resource) {}syntax. - Use
use()for closable resources. - The resource is closed automatically after the block.
- The resource is also closed if an exception is thrown.
- If you want to handle exceptions, wrap
use()intry/catch.
Common patterns
File("a.txt").bufferedReader().use { it.readText() }
File("a.txt").bufferedWriter().use { it.write("Hello") }
try {
File("a.txt").bufferedReader().use { println(it.readLine()) }
} catch (e: IOException) {
println("Read failed")
}
input.use { i ->
output.use { o ->
i.copyTo(o)
}
}
Remember
- is the idiomatic Kotlin replacement for Java try-with-resources.
FAQ
Is there a try-with-resources statement in Kotlin?
No. Kotlin does not have Java's try (...) {} syntax. The usual replacement is use().
What is the Kotlin equivalent of try-with-resources?
The idiomatic equivalent is calling use() on a closable resource:
File("data.txt").bufferedReader().use { it.readText() }
Does use() close the resource if an exception happens?
Yes. use() closes the resource whether the block succeeds or throws an exception.
Can I still use try/catch with use()?
Yes. Wrap the use() call in try/catch if you want to handle errors.
How do I manage two resources in Kotlin?
Usually by nesting use() blocks.
input.use { i ->
output.use { o ->
i.copyTo(o)
}
}
Is use() better than manually calling ?
Mini Project
Description
Build a small Kotlin program that writes text to a file and then reads it back safely using use(). This demonstrates the Kotlin way to manage resources without Java's try-with-resources syntax.
Goal
Create a program that saves a message to a file, reads the file contents, and prints them while ensuring all resources are automatically closed.
Requirements
- Create or open a text file.
- Write at least two lines into the file.
- Read the full contents back from the file.
- Print the contents to the console.
- Use
use()for both writing and reading.
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
Allow HTTP and HTTPS in Android 9 Pie with Network Security Configuration
Learn how Android 9 Pie handles cleartext HTTP traffic and how to allow HTTP and HTTPS safely using network security config.
Android AlarmManager Example: Scheduling Tasks with AlarmManager
Learn how to use Android AlarmManager to schedule tasks, set alarms, and handle broadcasts with a simple beginner example.