skip to content

What is the difference between require(...) and check(...) in the Kotlin standard library, and which exception does each throw?

level: juniorimportance: must knowfreq 70%

answer

  1. require = argument = IllegalArgumentException
  2. check = state = IllegalStateException
  3. Lazy message lambda runs only on failure
  4. Both inline, both always active
  5. error(msg) = throw IllegalStateException

basics

~10 s

Both check a condition and throw if it is false. require is for bad arguments and throws IllegalArgumentException. check is for a bad object state and throws IllegalStateException.

solid answer

~40 s

Both are inline stdlib guard functions taking a Boolean. require(value) throws IllegalArgumentException when value is false; use it to validate function arguments at the start of a function. check(value) throws IllegalStateException when false; use it to assert that the object or program is in a valid state to proceed. Semantically: require blames the caller (bad input), check blames the current state. Both have an overload taking a lazy message lambda, require(value) { "msg" }, evaluated only on failure. requireNotNull and checkNotNull are the null-checking variants that also smart-cast the value to non-null. Neither is disabled in production (unlike assert). error(msg) is a shorthand that always throws IllegalStateException.

code

kotlin · 4 lines
kotlin
fun transfer(amount: Int, accountOpen: Boolean) {
    require(amount > 0) { "amount must be > 0, was $amount" } // IllegalArgumentException
    check(accountOpen) { "account must be open" }            // IllegalStateException
}

go deeper

for a junior

Knows require throws IllegalArgumentException for bad args and check throws IllegalStateException for bad state.

for a middle

Articulates the caller-vs-state intent and mentions the lazy message overload and that both are always active.

for a senior

Explains inlining (no lambda allocation), how exception type guides catch sites, and pairs the NotNull variants with smart-casting.

for a principal

Frames precondition choice as part of API contract design and error taxonomy, and how it interacts with global exception handling and observability.

## What these functions are Kotlin's standard library (in `kotlin.Preconditions.kt`) provides small `inline` guard functions that throw when a condition is violated. They make intent explicit and produce clear exceptions. ## require — validate arguments `require(condition)` throws `IllegalArgumentException` if `condition` is `false`. Use it for argument validation: the failure means the **caller** passed something invalid. ```kotlin fun withdraw(amount: Int) { require(amount > 0) { "amount must be positive, was $amount" } // ... } ``` `IllegalArgumentException` semantically signals "a method has been passed an illegal argument." ## check — validate state `check(condition)` throws `IllegalStateException` if `condition` is `false`. Use it when the **object's or program's state** is wrong for the operation, regardless of arguments. ```kotlin class Connection { private var open = false fun send(data: String) { check(open) { "connection is not open" } // ... } } ``` ## Choosing between them - `require` -> the **input** is bad -> `IllegalArgumentException`. - `check` -> the **state** is bad -> `IllegalStateException`. This distinction matters because callers may catch these exceptions differently, and the type documents whose fault the failure is. ## Lazy message and inlining Both take an optional `message: () -> Any` lambda evaluated **only on failure**, so building an expensive message string costs nothing on the happy path. Because the functions are `inline`, no lambda object is allocated. ## Not the same as assert Unlike `assert`, `require` and `check` are **always active** in production — they are normal exceptions, not toggled by a JVM flag.

  • Are require and check disabled in release builds like assert can be?
    No. They are ordinary functions that always throw; only assert is gated by the -ea / -enableassertions JVM flag.
  • Why use require instead of writing if (x) throw IllegalArgumentException(...)?
    It is shorter, communicates intent, gives a consistent exception type and message format, and (for the NotNull variants) smart-casts the value.

require checks the ticket you were handed (caller's fault); check confirms the gate is actually open (the system's state).

saying these in an interview costs you the question

  • Saying require throws IllegalStateException (it throws IllegalArgumentException)
  • Claiming require/check are stripped out in production
  • Using check for argument validation or require for state
  • Thinking the message is always evaluated even on success
  • Confusing them with assert

context