Java's IOException is a checked exception. What happens in Kotlin when you call a Java method that declares `throws IOException`?
answer
- Kotlin has zero checked exceptions
- Java `throws IOException` → no try/catch forced in Kotlin
- Exception still thrown at runtime — handle if meaningful
- @Throws restores the throws clause for Java callers
- All exceptions behave like RuntimeException to the compiler
basics
~10 sNothing is forced. Kotlin has no checked exceptions, so the compiler does not make you write try/catch or declare the exception. You may catch it if you want, but you don't have to.
solid answer
~40 sKotlin does not enforce checked exceptions. A Java method's `throws IOException` clause imposes **no** compile-time obligation in Kotlin: you are not required to wrap the call in try/catch nor to declare anything. The exception is still thrown at runtime and can propagate up the stack like any unchecked exception, so you *should* still handle it where it matters — Kotlin just won't force you. This removes the boilerplate of rethrowing/wrapping checked exceptions through layers. The reverse concern: when Kotlin code is called *from* Java and you want a Java caller to be allowed (or required) to catch a checked type, annotate the Kotlin function with `@Throws(IOException::class)` so the `throws` clause appears in the generated bytecode; without it, Java cannot `catch (IOException e)` a Kotlin-thrown checked exception without a compile error.
code
kotlin · 7 lines// Calling Java that declares throws IOException — no try/catch required
fun loadConfig(path: String): String =
java.io.File(path).readText() // may throw IOException; compiler won't force handling
// Reverse: let Java callers catch a Kotlin-thrown checked exception
@Throws(java.io.IOException::class)
fun save(path: String, text: String) = java.io.File(path).writeText(text)go deeper
Knows Kotlin doesn't force try/catch for Java checked exceptions.
Explains 'no checked exceptions', that it still throws at runtime, and that you should still handle real I/O.
Adds @Throws for the Java-calls-Kotlin reverse direction and the rationale (lambda/functional friction) behind dropping checked exceptions.
Weighs the API-design trade-offs (error modeling via sealed Result types vs exceptions) and interop contracts across a mixed Kotlin/Java codebase.
## Checked vs unchecked — the Java background In Java, exceptions that extend `Exception` but not `RuntimeException` are **checked**: the compiler forces you to either `catch` them or declare them in the method's `throws` clause. `IOException`, `SQLException`, and `InterruptedException` are classic examples. This is enforced at compile time. ## Kotlin's rule: no checked exceptions Kotlin **does not have checked exceptions at all**. Every exception is treated like a Java `RuntimeException` from the compiler's perspective. Consequently, when you call a Java method that declares `throws IOException`: - The compiler does **not** require a try/catch. - The compiler does **not** require you to re-declare the exception. - The exception is still **thrown at runtime** and propagates normally. ```kotlin import java.io.BufferedReader import java.io.FileReader fun readFirstLine(path: String): String? { // FileReader/BufferedReader.readLine() declare throws IOException in Java // Kotlin requires NO try/catch here. val reader = BufferedReader(FileReader(path)) return reader.use { it.readLine() } // `use` closes it, still no forced catch } ``` ## Why Kotlin made this choice Checked exceptions cause boilerplate: rethrowing or wrapping through layers, empty `catch` blocks, and leaky abstractions in functional code (lambdas can't transparently throw checked exceptions). Kotlin's designers concluded the costs outweigh the benefits, so they dropped the enforcement. You can — and for real I/O **should** — still catch what you can meaningfully handle: ```kotlin try { readFirstLine("data.txt") } catch (e: java.io.IOException) { // allowed, just not required log.warn("read failed", e) } ``` ## The reverse direction: @Throws Problem arises when **Java calls Kotlin**. If a Kotlin function throws a checked exception, the generated bytecode has no `throws` clause, so a Java caller writing `catch (IOException e)` gets *"exception is never thrown in the corresponding try block"*. Fix it with the **`@Throws`** annotation: ```kotlin @Throws(java.io.IOException::class) fun writeFile(path: String) { /* ... */ } ``` Now the compiled method declares `throws IOException`, so Java code can catch or declare it. `@Throws` is purely for Java interop; it changes nothing for Kotlin callers. ## Key keywords/APIs No checked exceptions; `try`/`catch`; `@Throws(...::class)` for Java interop; `use` (the closeable extension that still doesn't force a catch).
- If Kotlin doesn't force handling, can an IOException still crash the program?Yes. It propagates up like any unchecked exception and will terminate the thread/program if never caught. Kotlin removes the compile check, not the runtime behavior.
- When do you actually need @Throws?Only when Kotlin code is called from Java and the Java side must catch or declare a specific checked exception type, or for frameworks that inspect the throws clause (e.g. some JUnit/RMI cases).
Java's checked exceptions are a seatbelt alarm that won't let you drive; Kotlin removed the alarm — the seatbelt still exists, you just have to choose to buckle up.
saying these in an interview costs you the question
- Saying Kotlin forces try/catch on Java checked exceptions
- Claiming the exception is silently swallowed (it isn't — it propagates)
- Thinking @Throws affects Kotlin callers' obligations
- Believing Kotlin converts checked exceptions into something safe at runtime