🥅
Exceptions

Exception Handling

Catching Errors
💡 try-catch is like a safety net at the circus — if the performer (the code) falls (an error occurs), the net (catch) catches it so the show (the program) doesn't crash.

You put code that might error out inside the try block. If an error occurs, the catch block "catches" it and the program doesn't crash.

The finally block always runs — whether an error occurred or not — like doing cleanup, closing files.

try {
  int x = 10 / 0;
} catch (ArithmeticException e) {
  System.out.println("Cannot divide by zero!");
} finally {
  System.out.println("Done trying.");
}
🥅
try-catch is like a safety net at the circus — if the performer (the code) falls (an error occurs), the net (catch) catches it so the show (the program) doesn't crash.
1 / 5
⚡ Quick Recap
  • try = risky code
  • catch = catches the error
  • finally = always runs
On this page (4 subtopics)

Everything starts from Throwable, which has two main branches: Error (serious JVM-level problems like OutOfMemoryError, StackOverflowError — normally not caught, there's nothing to do about them, the environment itself is broken) and Exception (program-level problems that can be handled).

Inside Exception there are also two groups: RuntimeException (and its subclasses — "unchecked", like NullPointerException) and everything else ("checked", like IOException). This distinction is covered in detail in the next subtopic.

LevelExamplesShould you handle it?
Throwable(root of everything)
ErrorOutOfMemoryError, StackOverflowErrorNormally not (environment issue)
Checked ExceptionIOException, SQLExceptionYes, the compiler forces it
RuntimeException (unchecked)NullPointerException, ArithmeticExceptionOptional, but good practice

NullPointerException (NPE) is the most common — when you call a method or access a field on a null object. ArrayIndexOutOfBoundsException — array index out of range (like accessing index 5 on a size-5 array, when valid indices are 0-4). ArithmeticException — like dividing an integer by 0 (10/0 throws an exception, but 10.0/0 doesn't — a double gives "Infinity" instead!).

ClassCastException — an invalid type cast (like Object o = "text"; Integer i = (Integer) o;). NumberFormatException — like Integer.parseInt("abc") (which isn't a number at all). IllegalArgumentException — an invalid/illegal argument passed to a method (like a negative age).

ExceptionWhen It Happens
NullPointerExceptionMethod/field access on a null object
ArrayIndexOutOfBoundsExceptionInvalid array index
ArithmeticExceptionDividing an integer by 0
ClassCastExceptionInvalid type cast
NumberFormatExceptionConverting an invalid String to a number
IllegalArgumentExceptionInvalid argument to a method

If the try block has a return statement, finally still runs *before* the return actually happens — Java guarantees finally's execution.

And if finally itself has a return, it "overrides" the try/catch's return — this is confusing behavior (the try's return value is silently discarded), which is why writing a return inside a finally block is a best-practice no-no.

static int test() {
  try {
    return 1;
  } finally {
    System.out.println("finally chalega return se pehle bhi");
    // return 2; // agar ye line hoti, to method 2 return karta, 1 nahi!
  }
}
⚠️Common Mistake: Writing return or throw inside a finally block is an anti-pattern — it can silently override the result of try/catch, turning debugging into a nightmare. Use finally for cleanup, not control flow.

Avoid a generic "catch (Exception e)" — catch the specific exception (like catch (IOException e)) so you know exactly what went wrong, and unrelated exceptions don't accidentally get "swallowed".

Never write an empty catch block (catch(e){}) — the error silently disappears and debugging becomes a nightmare. At the very least, log it (e.printStackTrace() or a proper logging framework).

Keep exception messages meaningful — "Error occurred" tells you nothing, "Failed to connect to database at " + url is far more useful for debugging.