1. What Is It?

try / catch / finally is the syntax for handling exceptions. You put risky code in a try block, specify what to do on failure in catch (Python calls it except), and put cleanup code in finally — which runs whether the try succeeded, failed, or returned early.

Without this construct, a single failing operation somewhere deep in a call would either crash the whole program or silently corrupt state. With it, you can draw clear boundaries: "beyond this line I handle failure; inside the block I assume success."

Quick check

A backend service connects to a database and performs a query. The database connection must be closed after the operation, regardless of whether the query succeeds or throws an exception. Which block in a try/catch/finally construct is the right place to put the connection-closing logic?

Choose one answer

2. How It Works

The runtime models execution as three outcomes of the try block: normal completion, thrown, or early return/break. The catch/except clauses are matched against the 's type. finally always runs, after the try and any matching handler.

# Python
f = None
try:
    f = open("data.txt")
    data = f.read()
    process(data)
except FileNotFoundError as e:
    print("no file:", e)
except PermissionError as e:
    print("permission:", e)
except Exception as e:             # catch-all, rarely what you want
    print("something else:", e)
else:                              # runs only if no exception was raised
    print("success")
finally:
    if f is not None:              # finally runs ALWAYS; open() may have failed
        f.close()

Handler matching

Handlers are tried top-down; the first matching type wins. This is why you put more specific types first: catch (NoSuchFileException) before catch (IOException). A generic handler at the top would swallow the more specific case.

Resource management: the real reason finally exists

Code often acquires resources (files, sockets, locks) that must be released whether things succeed or fail. finally guarantees that.

Python 2.5+ has a cleaner pattern: context managers (with).

with open("data.txt") as f:
    process(f.read())
# f.close() happens automatically, even on exception

Java 7+ has try-with-resources:

try (var f = Files.newBufferedReader(path)) {
    process(f.readLine());
}  // f.close() happens automatically

C++ doesn't have finally — it has RAII (Resource Acquisition Is Initialization). The destructor of a -allocated runs automatically when the exits, whether by normal return or by exception unwinding.

{
    std::ifstream f("data.txt");   // constructor acquires
    process(read_all(f));
}  // destructor releases — even if exception is thrown

Match the exception, then clean up

A PermissionError from process skips the first handler, reaches the matching handler, and still closes the file in finally.

The try block groups work that may fail.

Text version
  1. The try block groups work that may fail.
  2. The file opens and reads data so process can use its contents.
  3. Processing raises PermissionError.
  4. Python checks handlers from top to bottom, skips FileNotFoundError because the type differs, and matches PermissionError.
  5. Only the first matching handler runs and prints the error.
  6. The error skips else, but finally still closes the file.
Quick check

A backend service opens a database connection and runs a query inside a try block. You add two catch clauses: the first catches a specific DeadlockException, and the second catches a broader DatabaseException (which DeadlockException is a subclass of). In what order should these handlers be declared, and why?

Choose one answer

3. What You Actually Need to Know

  • Don't catch what you can't handle. catch ( e) {} — catching every and doing nothing — is almost always a bug. At minimum, log it and rethrow; usually, let it propagate to a place that can actually respond.
  • Catch specific types, not base classes unless you genuinely want every subclass. except Exception: in Python will also catch KeyboardInterrupt in older versions — use except BaseException: only if you mean it. Modern guidance: catch , not BaseException.
  • finally runs even if you return inside try. This is load-bearing. It also runs if the exception is rethrown. It does NOT run if the process is killed (kill -9, os._exit(), segfault). sys.exit() raises SystemExit, so finally still runs.
  • A return inside finally overrides any return or exception from try. This is almost always a bug — the original exception disappears silently.
  • Don't use exceptions for control flow. try: while True: x = next(it) except StopIteration: ... is the Python iterator idiom, but in most cases a conditional check is clearer and faster.
  • Narrow your try block. Wrap only the operation that can fail, not the surrounding code. Broad try blocks hide which line caused the failure.
  • Exception chaining preserves the original cause. Python: raise NewError("...") from original. Java: throw new MyException("...", original). Don't lose the original trace when rethrowing.
  • Debugging clues:
    • Resource leak (file handle, lock) after an exception → missing finally / context manager / RAII.
    • "Weird" behavior where errors vanish → return inside finally or a blanket except:.
    • trace points at the wrong place → the real failure was caught and rewrapped without from / chaining.

Cleanup happens before an early return

A return inside try waits while finally runs. If cleanup finishes normally, the original return proceeds.

Returning inside try still requires cleanup before the function exits.

Text version
  1. Returning inside try still requires cleanup before the function exits.
  2. The runtime runs finally before it returns to the caller.
  3. If cleanup finishes normally, the original return proceeds, but a return inside finally would replace it.
Quick check

A backend service processes file uploads. The upload handler has a finally block that closes the file handle and releases a lock. A developer adds a return success_response inside the finally block to ensure a response is always sent. What is the most significant risk of this pattern?

Choose one answer

4. Language Differences

AspectPythonJavaC++
Keywordtry / except / else / finallytry / catch / finallytry / catch (no finally)
Cleanup patternfinally or withfinally or try-with-resourcesRAII (destructors)
Catch-allexcept: (not recommended) or except Exception:catch (Throwable t) (catch (Exception e) misses Error)catch (...)
Can catch by type hierarchyYesYesYes
else block (runs on success)YesNoNo
Rethrowraise (bare)throw e;throw; (preserves type)
Exception chainingraise X from ePass cause to constructorstd::throw_with_nested / manual

Python's else is under-used: it lets you say "if the try succeeds, do this" without widening the try block. Cleaner than adding more code inside try.

Cleanup patterns across three languages

Python and Java offer finally and resource constructs, while C++ ties cleanup to destructors through RAII.

Python and Java have finally, while C plus plus uses other cleanup mechanisms.

Text version
  1. Python and Java have finally, while C plus plus uses other cleanup mechanisms.
  2. Python uses the with statement, Java uses try with resources, and C plus plus releases resources in destructors.
  3. Python runs else only when try finishes normally, without an exception or an early exit.
Quick check

A Python backend developer writes a function that opens a database connection, runs a query inside a try block, and wants to execute some result-processing logic only when the query succeeds — without expanding the try block to include that logic. Which language construct best fits this goal in Python?

Choose one answer

5. Tradeoffs & Decisions

  • Where to catch: close to the error vs. high in the call . Close-to-the-error catches let you retry or substitute a default. High-level catches (e.g., one per web request) turn arbitrary failures into a clean 500 response. Most real systems do both — local for recovery, global for last-resort logging.
  • finally vs. context managers / RAII. Context managers and RAII are declarative — the cleanup is tied to the resource's type, not copied at every call site. Prefer them. finally is for one-off ad-hoc cleanup that doesn't fit a resource pattern.
  • Rethrowing vs. wrapping. Rethrow when you can't add context. Wrap (with from e / chaining) when you want a domain-meaningful that still preserves the root cause.
  • Silent swallow vs. loud failure. Silent swallow is a debugging nightmare. If you genuinely must ignore an error (best effort), at least log it. Better: return a success/failure indicator to the caller.

If you see a broad try: ... except : pass, it usually hides a real bug that's happened for months. You'd choose a narrow catch of a specific type, do something meaningful with it (log, retry, return a default), and let everything else propagate.

Quick check

A backend service connects to a third-party payment API. A developer writes the following code: try: result = payment_api.charge(amount) except Exception: pass During a production incident, charges are silently failing for hours without anyone noticing. Which refactoring best addresses this problem?

Choose one answer

6. Interview Cheat Sheet

  • try contains risky code; catch/except handles specific types; finally runs no matter what (success, failure, or return).
  • Handlers match top-down by type — put specific exceptions before general ones.
  • finally is for cleanup that must run, typically releasing resources — but context managers (with) and try-with-resources / RAII are usually cleaner.
  • Never silently swallow exceptions — at minimum log them; usually let them propagate.
  • Don't use exceptions for control flow — they're slow and obscure intent.
  • C++ has no finally — it uses RAII, where destructors automatically release resources on exit.

Follow-ups:

  • "Does finally run if you return inside try?" — Yes. It also runs on or break. Not if the process is killed.
  • "Why is catch (Exception e) bad?" — It catches every Exception, including bugs like NullPointerException you probably wanted to know about. Prefer specific types.
  • "Why doesn't C++ have finally?" — Because RAII makes it unnecessary. A -allocated 's destructor runs automatically when the exits, even during exception unwinding.

Reading

On this page

My notes

Sign in to keep highlights and notes.

Glossary history

Click dotted jargon to save explanations here.