skip to content

How Kotlin Does Its Standard Library

Kotlin's stdlib has a consistent shape: value-based error handling with Result, behavior attached to properties through delegates, scoped resources via use, and inline helpers that leave no trace at runtime. Recognizing that shape makes the individual APIs easy to predict.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

What does the stdlib `use` function do, and why is it preferred over manually calling `close()` on a resource?

level: juniorimportance: must knowfreq 70%

answer

  1. inline extension on Closeable/AutoCloseable
  2. close() in finally, always
  3. addSuppressed keeps original error
  4. Kotlin's try-with-resources
  5. returns the lambda's value

basics

~10 s

use runs your code with a resource like a file, then automatically closes it afterward, even if an error happens. It saves you from forgetting to close it yourself.

solid answer

~40 s

`use` is an inline extension function on `Closeable`/`AutoCloseable`. You write `reader.use { r -> ... }`; it executes the lambda, then guarantees `close()` is called in a `finally` block whether the block returns normally or throws. This is Kotlin's equivalent of Java's try-with-resources. If the block throws and `close()` also throws, the close exception is added as a suppressed exception on the original (via `addSuppressed`), so the original error is not lost. Because `use` is `inline`, the lambda body is inlined at the call site with no extra object allocation. The return value of `use` is whatever the lambda returns, so you can compute and return a result directly: `val text = file.bufferedReader().use { it.readText() }`. Always prefer it over manual `try/finally { close() }`.

code

kotlin · 2 lines
kotlin
val lines: List<String> = File("in.txt").bufferedReader().use { it.readLines() }
// reader is closed here, even if readLines() throws

go deeper

for a junior

Knows use auto-closes the resource and replaces manual close().

for a middle

Explains the finally semantics and that use returns the lambda value.

for a senior

Discusses addSuppressed, inline (no allocation), and the AutoCloseable overload.

for a principal

Frames use as the stdlib's deliberate mapping of try-with-resources onto an inline function, and reasons about exception-masking guarantees in library APIs.

## What `use` is `use` is a standard-library **extension function** declared (roughly) as `inline fun <T : Closeable?, R> T.use(block: (T) -> R): R`. There is also an overload for `AutoCloseable`. It models **scoped resource management**: a resource is acquired, used inside a block, then deterministically released. ## Why it exists Files, sockets, streams, and database connections hold OS-level handles that must be released. If you forget to call `close()`, you leak handles. Manual `try/finally` is verbose and easy to get wrong (e.g. swallowing the real exception). `use` packages the correct pattern once. ## How it works internally Conceptually: ```kotlin inline fun <T : Closeable?, R> T.use(block: (T) -> R): R { var exception: Throwable? = null try { return block(this) } catch (e: Throwable) { exception = e throw e } finally { when { this == null -> {} exception == null -> this.close() else -> try { this.close() } catch (closeEx: Throwable) { exception.addSuppressed(closeEx) } } } } ``` Key points: - **`finally`** guarantees `close()` runs on normal return *and* on exception. - If the block threw and `close()` *also* throws, the close exception is attached with **`addSuppressed`** so the primary failure is preserved. You can see it later via `Throwable.suppressed`. - It is **`inline`**, so the lambda is inlined — no `Function` object is allocated and `return`/`break` behave naturally. ## Typical usage ```kotlin val text = File("data.txt").bufferedReader().use { reader -> reader.readText() } ``` The value of the `use` expression is the lambda's last expression, so you can return computed data straight out of it. ## Relationship to Java This is Kotlin's counterpart to Java's **try-with-resources**. Kotlin chose a library function (`use`) plus lambdas instead of dedicated syntax, which is a recurring theme in the stdlib: runtime concepts are mapped onto inline functions rather than new keywords.

  • What happens if both the block and close() throw?
    The block's exception propagates; the close() exception is attached to it via addSuppressed and retrievable from Throwable.suppressed.
  • Can use return a value?
    Yes — use returns whatever the lambda returns, so you can compute and return a result directly.

Like a self-locking door: you walk through, do your thing, and it locks behind you no matter how you leave.

saying these in an interview costs you the question

  • Claiming use only works on files
  • Saying you still need a manual finally with use
  • Thinking close() runs only on success, not on exception
  • Believing the close exception overwrites/hides the original error
  • Not knowing use returns the lambda result

context

open as a page

How does `by lazy` work as a delegated property, and what does the `LazyThreadSafetyMode` argument control?

level: middleimportance: must knowfreq 65%

basics

~10 s

by lazy computes a value the first time you read the property, then caches it for later reads. The mode setting controls whether that first computation is safe when many threads read at once.

open as a page

Explain `Result<T>` in the Kotlin stdlib: how it represents success/failure, how to create and consume it, and its key limitations.

level: middleimportance: should knowfreq 60%

basics

~10 s

Result<T> holds either a successful value or a thrown error, without using exceptions to control flow. You can check which one it is and transform the value safely.

open as a page

Why are stdlib helpers like the scope functions (`let`, `run`, `apply`, `also`, `with`) and `repeat` declared `inline`, and what does that buy you?

level: seniorimportance: should knowfreq 45%

basics

~20 s

These helpers are marked inline, so the compiler copies their code straight into the call site. That avoids creating an extra function object for the lambda, making them as cheap as writing the code by hand.

open as a page

What do `Delegates.observable` and `Delegates.vetoable` provide, and how do they differ?

level: seniorimportance: should knowfreq 40%

basics

~10 s

Both let you run code whenever a property changes. observable notifies you after a change happened; vetoable lets you inspect the new value first and reject it so the property keeps its old value.

open as a page