💥 Exceptions & Errors · Intermediate

throw vs throws in Java

throw raises an exception; throws declares it in a signature.

🧩 The mysterythrow and throws — one letter apart. Mix them up and the compiler stops you cold. Do you know which one pulls the alarm and which one just warns?

Pull the alarm: throw

**throw is a statement inside a method body. It raises one exception object** right now. Java has no raise keyword — it's always throw plus an object.

void setAge(int age) {
    if (age < 0)
        throw new IllegalArgumentException("age");
    this.age = age;
}

Post a warning sign: throws

**throws belongs in the method signature. It tells callers which checked exceptions may escape — and it's required for them. You throw one object, but you can declare several types**: throws IOException, SQLException.

String load(Path p) throws IOException {
    return Files.readString(p);
}
🔮 Predict it

Leaving the loop

The catch is outside the loop. What prints?

void check(int n) {
    if (n > 2) throw new RuntimeException();
    System.out.print(n);
}
void main() {
    try {
        for (int i = 1; i < 6; i++) check(i);
    } catch (RuntimeException e) {
        System.out.print("!");
    }
}
  1. 12!
  2. 12!45
  3. 123!
  4. 12345
Show the answer

check prints 1 and 2, then throws on 3. The exception leaves check, then the loop, until the catch outside it. So 3, 4 and 5 are never printed.

⚠️ The trap

Swapping the keywords

throws inside a body or throw in a signature are both compile errors. Memory trick: throws has an s because it can list several types in the signature.

void bad() throw IOException { }   // error
void bad2() {
    throws new RuntimeException();  // error
}

Overrides can't add surprises

Code holding a Reader expects read() to throw no checked exceptions. So an override can't declare new or broader checked exceptions — that's a compile error. It may declare fewer or narrower ones.

class Reader {
    void read() { }
}
class FastReader extends Reader {
    @Override
    void read() throws Exception { } // error
}
🤔 Think first

Declaring unchecked ones?

May you write throws IllegalArgumentException on a method?

Think about it, then reveal the answer

Yes — it's allowed but optional. throws is only *required* for checked exceptions; listing unchecked ones simply documents them for readers.

💼 In the real world

Throw early, declare honestly

Professional code validates inputs at the top of public methods and throws IllegalArgumentException with a clear message. File and network utilities declare throws IOException, leaving the decision — retry, fallback, or fail — to the caller, who knows the context.

Key takeaways

  1. throw + an object: throw new X(...)
  2. throws + one or more types in the method signature
  3. Checked exceptions that escape a method must appear in throws
  4. An override can't declare new or broader checked exceptions
🤯 Did you know?

Checked exceptions are purely a compiler rule — the JVM itself never checks throws clauses. That's why Kotlin code can throw an IOException without declaring anything.

Practice questions

Which keyword fills the blank?

void setAge(int age) {
    if (age < 0)
        ___ new IllegalArgumentException("age");
    this.age = age;
}
  1. throw
  2. throws
  3. raise
  4. return
Check your answer

throw. throw raises a specific exception object. Java has no raise keyword.

Which keyword fills the blank?

String load(Path p) ___ IOException {
    return Files.readString(p);
}
  1. throws
  2. throw
  3. catches
  4. extends
Check your answer

throws. Files.readString can throw IOException, a checked exception, so the method must declare it with throws (or catch it).

Next: build your own exception — an InsufficientFundsException that knows exactly how much money is missing.