Contrast `use` with a manual `try/finally` and with scope functions like `apply`/`also`/`let`. When would you NOT reach for `use`?
answer
- use = try/finally + close + suppressed handling
- scope functions never close
- wrong if type isn't Closeable
- wrong if resource must outlive the block
- don't `use` framework/DI/pool/shared clients
basics
~20 suse is a focused try/finally that closes a resource; it isn't a general scope function. Don't use it for objects that aren't Closeable, or when the resource must outlive the block (e.g. you return it or a framework owns its lifecycle).
solid answer
~50 s`use` encapsulates the exact `try { block } finally { close() }` pattern plus suppressed-exception handling, so hand-writing try/finally just to close one resource is redundant and more error-prone. Unlike `apply`/`also`/`let`/`run` (the scope functions), `use` is not about readability of object configuration — it is specifically about deterministic resource release; scope functions never call `close()`. You should NOT use `use` when: the type is not `Closeable`/`AutoCloseable`; the resource is owned elsewhere and must stay open after the block (returning it from `use` yields a closed handle); a framework or DI container manages the lifecycle (Spring datasource connections, injected `OkHttpClient`); or the resource is long-lived/shared (a connection pool, a singleton client). For Kotlin coroutines or many short-lived items, prefer structured patterns over deeply nested `use`. Misusing `use` to close a shared client closes it for everyone.
code
kotlin · 6 lines// DON'T: closes a shared, injected client for everyone
class Service(private val client: OkHttpClient) {
fun bad(url: String) = client.use { it.newCall(/*...*/).execute() } // wrong
}
// DO: let the resource you own be used-and-closed
fun read(file: File) = file.bufferedReader().use { it.readText() }go deeper
Knows use closes and scope functions don't; may not list all the 'don't use' cases.
Distinguishes use from try/finally and from scope functions and avoids the let-instead-of-use leak.
Enumerates ownership/lifetime cases (DI, pools, shared clients) where use is wrong and reasons about resource boundaries.
Defines team conventions for resource ownership vs use, and catches shared-client use misuse in API and review guidelines.
## `use` vs manual `try/finally` `use` *is* a try/finally — a tested, inline one with suppressed-exception handling baked in. Writing your own: ```kotlin val r = open() try { work(r) } finally { r.close() } ``` works but invites mistakes: forgetting the finally, closing in the wrong place, not handling a close-time exception, or null-handling. `use` removes all of that, so prefer it for the single-resource case. ## `use` vs scope functions Kotlin's **scope functions** — `let`, `run`, `with`, `apply`, `also` — restructure code for readability (configuring an object, chaining, null-safety with `?.let`). **None of them close anything.** `use` is not a scope function; it is a resource-management function in `kotlin.io`. A classic bug is using `apply`/`also` where `use` was needed: ```kotlin // BUG: never closed val text = File("x").bufferedReader().let { it.readText() } // CORRECT val text = File("x").bufferedReader().use { it.readText() } ``` They look almost identical, which is exactly why this slips through review. ## When NOT to use `use` - **Not Closeable/AutoCloseable.** `use` only exists on those types; a plain domain object has no `close()`. - **Resource must outlive the block.** If you need to return the open resource to a caller, `use` is wrong — the resource is closed before `use` returns. Returning `it` gives a dead handle. - **Framework-/DI-owned lifecycle.** A Spring-managed JDBC `Connection` from a pool, an injected `OkHttpClient`, or a `HttpClient` configured as a singleton should be closed (or returned to the pool) by its owner, not by your `use`. Calling `use` on a shared client physically closes it for every other caller. - **Long-lived/shared resources.** Connection pools, thread pools, app-scoped clients live for the application's lifetime; wrapping them in `use` defeats reuse. - **Many resources / streaming pipelines.** Deeply nested `use` becomes unreadable; consider a list of resources closed in a loop, or higher-level helpers (`File.readText()`, `forEachLine`, `copyTo`) that wrap `use` internally. ## Rule of thumb Use `use` for a resource **you acquire and fully consume within a bounded scope**. If ownership, lifetime, or sharing crosses that boundary, manage it with the owner's lifecycle instead.
- Why is `bufferedReader().let { it.readText() }` a bug while `.use { it.readText() }` is correct?`let` returns the block result but never calls `close()`, so the reader leaks; `use` closes it in a finally.
- What's wrong with calling `use` on an injected singleton HTTP client?`use` calls `close()`, physically shutting the shared client down for all callers; its lifecycle belongs to the DI container, not your method.
use is a rental return slot — perfect for a thing you borrowed and finished with; useless (and harmful) for something the building owns and shares.
saying these in an interview costs you the question
- Treats `use` as interchangeable with `let`/`also`
- Calls `use` on a DI-managed/shared client or pooled connection
- Returns the resource from `use` to use it later
- Reimplements try/finally by hand for a single Closeable for no reason
- Thinks scope functions close resources