Exceptions Workbook


Practice problems for Unchecked and Unbothered. Each takes a minute or two. Write your own answer first, then click Show answer — nothing here is a trick question, just direct practice of the syntax from the lesson.

try and preconditions

1. try as an expression

Assign number the result of parsing text as an Int, or 0 if it isn’t a valid number — using try/catch as an expression.

Show answer Hide answer
val number = try {
    text.toInt()
} catch (e: NumberFormatException) {
    0
}

2. Require an argument

Write sqrt(x: Double) that requires x >= 0, throwing IllegalArgumentException with a message otherwise.

Show answer Hide answer
fun sqrt(x: Double): Double {
    require(x >= 0) { "x must be non-negative" }
    return Math.sqrt(x)
}

3. Check state

Inside a method, throw IllegalStateException when isClosed is true, using the precondition helper for state.

Show answer Hide answer
check(!isClosed) { "already closed" }

require is for arguments; check is for state.

resources and Result

4. Auto-close a resource

Read all text from a reader (an AutoCloseable), making sure it’s closed afterward.

Show answer Hide answer
reader.use { it.readText() }

use closes the resource whether the block succeeds or throws — Kotlin’s try-with-resources.

5. Capture success or failure

Use runCatching to parse text to an Int, returning -1 on failure.

Show answer Hide answer
runCatching { text.toInt() }.getOrElse { -1 }

6. A function that always throws

Write fail(message: String) whose return type tells the compiler control never continues past it.

Show answer Hide answer
fun fail(message: String): Nothing = throw IllegalStateException(message)

Nothing lets it stand in anywhere — e.g. val x = maybe ?: fail("missing").

the bigger picture

7. No checked exceptions

readFile() can throw IOException. Write a function that calls it and returns the result — with no try/catch and no throws clause.

Show answer Hide answer
fun load(): String {
    return readFile()   // no catch, no throws — Kotlin has no checked exceptions
}

8. Model errors as data

For a fetch that can fail in an expected way, declare a sealed FetchResult with Success(val user: User) and Error(val message: String) instead of throwing.

Show answer Hide answer
sealed class FetchResult {
    data class Success(val user: User) : FetchResult()
    data class Error(val message: String) : FetchResult()
}

Sealed result types make the failure path part of the return type, checked by an exhaustive when.

9. Get-or-null

Use runCatching to attempt risky() and produce its result or null.

Show answer Hide answer
runCatching { risky() }.getOrNull()

10. Catch is an expression too

Assign config from loadConfig(), falling back to Config.default() if it throws — in one expression.

Show answer Hide answer
val config = try { loadConfig() } catch (e: Exception) { Config.default() }

Back to the lesson, Unchecked and Unbothered, or on to the next one: Java interop.

Comments