skip to content

How does `use` propagate its return value, and how do you correctly handle two resources (e.g. an input and an output stream) with `use`?

level: middleimportance: should knowfreq 55%

answer

  1. use returns the block's last expression
  2. nest use-in-use for two resources
  3. inner closes first, then outer
  4. don't open both before the first use
  5. non-local return still closes (inline)

basics

~10 s

use returns whatever its lambda returns, so you can assign it directly. For two resources, nest one use inside another so both close in the right order.

solid answer

~40 s

`use` is generic in its return type `R`: the value of the lambda's last expression becomes the value of the `use` call, so `val data = stream.use { it.readBytes() }` works without a separate variable. For multiple resources you nest: open the outer one with `use`, and inside its block open the inner one with another `use`. The inner resource closes first (when its block ends), then the outer, mirroring the reverse-acquisition order of Java's try-with-resources. Because `use` is `inline`, a non-local `return` inside the block returns from the enclosing function and still triggers `close()` via the finally. Avoid opening both resources before the first `use` (e.g. on one line), because if the second open throws, the first is never wrapped and leaks.

code

kotlin · 6 lines
kotlin
fun copy(src: File, dst: File) =
    src.inputStream().use { input ->
        dst.outputStream().use { output ->
            input.copyTo(output)
        }
    }

go deeper

for a junior

Knows use returns a value and that you can put two use calls together for two resources.

for a middle

Writes correct nested use and explains return-value propagation and close ordering.

for a senior

Articulates the leak risk of opening resources outside use and the inline non-local-return behaviour.

for a principal

Sets a codebase convention (e.g. lint rule) for nested-use acquisition order and reviews resource-handling APIs for it.

## Return value `use` is declared `fun <T : Closeable?, R> T.use(block: (T) -> R): R`. The type parameter `R` is the lambda's result type, so the value of the **last expression** in the block is returned by `use`: ```kotlin val bytes: ByteArray = File("img.png").inputStream().use { it.readBytes() } ``` No intermediate variable for the stream is needed, and the stream is already closed by the time `bytes` is assigned. ## Nesting two resources The correct pattern is to nest, so each resource has its own `use` and its own finally: ```kotlin File("in.txt").inputStream().use { input -> File("out.txt").outputStream().use { output -> input.copyTo(output) } } ``` - The **inner** `use` (`output`) closes first, when the inner block ends. - The **outer** `use` (`input`) closes second. - This reverse order matches Java's try-with-resources and is what you want: you finish writing/flushing the output before tearing down the input. ## Why not open both up front This is subtly wrong: ```kotlin // risky val input = File("in.txt").inputStream() val output = File("out.txt").outputStream() // if THIS throws, input leaks input.use { output.use { input.copyTo(output) } } ``` If the second `inputStream()`/`outputStream()` constructor throws, the first resource was acquired but never entered a `use`, so it leaks. Nesting acquires each resource **inside** the protection of the previous `use`. ## Inline and non-local return Because `use` is `inline`, the lambda is not a separate function. A `return` inside it returns from the **enclosing** function, and the finally still runs `close()` first: ```kotlin fun firstNonBlank(file: File): String? = file.bufferedReader().use { r -> for (line in r.lineSequence()) if (line.isNotBlank()) return line // closes r, then returns null } ``` ## Returning the resource itself is a bug Never do `socket.use { it }` to "get the resource out" — it is closed by the time `use` returns, so you would hold a dead handle.

  • In nested `use`, which resource closes first and why does it matter?
    The innermost one. For copy/streaming you must finish and flush the output (inner) before closing the input (outer), matching try-with-resources reverse order.
  • Can you `return` out of the enclosing function from inside a `use` block?
    Yes — `use` is inline, so a non-local return works and the resource is still closed by the finally before control leaves.

saying these in an interview costs you the question

  • Opens both resources on separate lines before any `use`, leaking on failure
  • Thinks you cannot return a value from `use`
  • Returns the resource itself from the block and uses it afterwards
  • Believes nesting closes the outer resource first
  • Adds a try/finally inside the `use` block, duplicating its job

context