skip to content

@Throws For Checked Exceptions

Since Kotlin has no checked exceptions, @Throws is what emits a throws clause so Java callers can catch or declare it. On Kotlin/Native it does more than documentation, which is a nice connection to make.

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

questions

5

Kotlin has no checked exceptions. What does the @Throws annotation do, and why would you put it on a Kotlin function?

level: juniorimportance: must knowfreq 55%

answer

  1. Kotlin = all exceptions unchecked
  2. @Throws emits Java 'throws' clause in bytecode
  3. Interop-only: no effect on Kotlin callers
  4. Fixes Java 'exception never thrown' error
  5. vararg of KClass: @Throws(IOException::class)

basics

~20 s

Kotlin never forces you to declare or catch exceptions. @Throws tells the compiler to add a Java 'throws' clause to the generated method, so Java code calling that Kotlin function can catch or declare the exception normally.

solid answer

~40 s

In Kotlin every exception is unchecked, so the bytecode of a Kotlin function carries no `throws` clause by default. That is fine for Kotlin-to-Kotlin calls, but Java has checked exceptions: a Java caller cannot `catch (IOException e)` unless the called method declares it, and tools/compilers complain. Annotating the Kotlin function with `@Throws(IOException::class)` makes the Kotlin compiler emit `throws IOException` in the generated JVM method signature. Now Java callers can `catch` it without an 'exception never thrown' error, or declare it on their own method. It is purely an interop hint: it changes the bytecode signature for Java's benefit and has no effect on Kotlin callers, who still are not required to handle anything.

code

kotlin · 9 lines
kotlin
import java.io.IOException

@Throws(IOException::class)
fun readConfig(path: String): String =
    java.io.File(path).readText()

// Java side (now legal):
// try { Configs.readConfig("a.txt"); }
// catch (IOException e) { /* handle */ }

go deeper

for a junior

Knows Kotlin has no checked exceptions and that @Throws adds a Java throws clause for interop.

for a middle

Can explain the Java 'exception never thrown' compile error it prevents and that it is signature-only.

for a senior

Frames it as a public-API interop decision and notes it accepts a vararg of KClass with no runtime effect.

for a principal

Discusses API-design policy: when to expose checked-style contracts to Java consumers vs. keeping a pure-Kotlin surface.

## Background: checked vs unchecked exceptions In **Java**, exceptions are split into two groups. **Checked** exceptions (subtypes of `Exception` that are not `RuntimeException`, e.g. `IOException`) must be either caught with `try/catch` or declared with a `throws` clause on the method — the Java compiler enforces this. **Unchecked** exceptions (`RuntimeException` and `Error` subtypes) need no declaration. **Kotlin has no checked exceptions at all.** Every exception is treated like an unchecked one: you are never *required* to catch or declare anything. This is a deliberate language decision. ## The interop problem When Kotlin compiles a function, the generated JVM method has **no `throws` clause** by default. For Kotlin callers this is invisible and harmless. But a **Java** caller sees a method that declares it throws nothing. If the Java code writes: ```java try { kotlinReadFile(); } catch (IOException e) { ... } // compile error in Java ``` the Java compiler rejects it with *"exception IOException is never thrown in the corresponding try block"*, because the method signature does not declare `IOException`. ## What `@Throws` does `@Throws(vararg exceptionClasses: KClass<out Throwable>)` instructs the Kotlin compiler to write those exception types into the **`throws` clause of the generated JVM method**. It does **not** change runtime behavior, does not wrap anything, and does not affect Kotlin callers — it only edits the method's bytecode signature so Java sees a normal checked-exception declaration. ```kotlin import java.io.IOException @Throws(IOException::class) fun readConfig(path: String): String { // may throw IOException at runtime return java.io.File(path).readText() } ``` The generated method becomes the Java-visible `String readConfig(String) throws IOException`. ## Key facts - It accepts a **vararg** of `KClass` references, so you can list several: `@Throws(IOException::class, TimeoutException::class)`. - It is **interop-only**: Kotlin callers gain nothing and are still not forced to handle the exception. - It does not make Kotlin enforce anything — the function can throw the listed types or not; the annotation is purely a signature hint. - The fully qualified name is `kotlin.Throws` (in package `kotlin`, auto-imported). ## When to use it Use it on Kotlin functions that are part of a **public API consumed from Java** and that legitimately throw a checked exception Java callers should handle — e.g. I/O, parsing, or `Closeable.close()`. If your code is Kotlin-only, you almost never need it.

  • Does @Throws change anything for a Kotlin caller of the function?
    No. Kotlin callers are never forced to catch or declare; the annotation only adds the throws clause to the JVM signature for Java's benefit.
  • Can you list more than one exception?
    Yes — it is a vararg: @Throws(IOException::class, TimeoutException::class).

@Throws is a translator's note added to a contract so a Java reader (who insists every risk be written down) accepts it; the Kotlin reader ignores the note entirely.

saying these in an interview costs you the question

  • Claiming @Throws makes Kotlin enforce checked exceptions
  • Saying it wraps or rethrows the exception at runtime
  • Thinking it affects Kotlin callers, not just Java interop
  • Believing Kotlin has checked exceptions like Java

context

open as a page

If you annotate a Kotlin function with @Throws, does it force other Kotlin code to catch the exception? Explain what changes and what does not.

level: middleimportance: must knowfreq 45%

basics

~10 s

No. @Throws never forces Kotlin callers to do anything — Kotlin has no checked exceptions. It only changes the generated JVM method signature so Java callers can catch or declare the exception.

open as a page

Several Kotlin stdlib functions (like readText or use) already carry @Throws. Why, and what is the common pitfall when a Kotlin function delegates to Java code that throws a checked exception without re-declaring it?

level: middleimportance: should knowfreq 28%

basics

~20 s

Stdlib functions that wrap Java I/O carry @Throws so Java callers can handle the IOException Java would normally force them to. The pitfall: your own Kotlin wrapper around Java I/O won't declare anything unless you add @Throws yourself, so Java callers can't catch it.

open as a page

You want a suspend function and a SAM interface implementation to declare a checked exception to Java callers. Where exactly do you place @Throws, and what are the gotchas?

level: seniorimportance: should knowfreq 30%

basics

~20 s

Put @Throws directly on the function or property accessor whose generated method should carry the throws clause. For suspend functions you can annotate them, but the clause lands on the suspending bytecode method; lambdas can't be annotated, so use an explicit function or object.

open as a page

You own a Kotlin library consumed by both Kotlin and Java teams. Design a policy for using @Throws across the public API, addressing compatibility, documentation, and the trade-offs of exposing checked-exception contracts.

level: principalimportance: nice to knowfreq 14%

basics

~20 s

Add @Throws only on public methods Java teams call that genuinely throw a checked exception worth handling. Treat the throws clause as part of your binary contract: adding/removing it can break Java callers. Document it and keep it stable.

open as a page