EMZETT.
Login

Exceptions

In short: A mechanism that lets a program react to unexpected errors at runtime without immediately crashing entirely — an error is “thrown” and can be specifically “caught” and handled elsewhere in the code.

In more detail: Instead of manually checking return values for error codes, an exception interrupts the normal program flow and jumps to the next matching error-handling block (try/catch). This separates the “happy path” code from the error-handling code and prevents an overlooked error from silently continuing. For several possible error types, different handling blocks can be defined.

In Depth

try:
    result = 10 / input_value
except ZeroDivisionError:
    print("Division by zero is not allowed")
except ValueError:
    print("Input was not a valid number")
else:
    print("Successfully calculated:", result)
finally:
    print("This block ALWAYS runs, error or not")

The flow when “throwing” an exception (also “raise”): as soon as an error occurs, the runtime environment immediately interrupts normal execution at exactly that spot and searches — walking up the call stack — for the next matching catch/except block that can handle this type of error. If none is found (the exception “breaks through” all the way to the top), the program crashes and shows a stack trace.

This “interrupt and pass upward” is the decisive advantage over error codes as a return value: an error code can be accidentally ignored (the caller simply doesn’t check the return value), and the code continues running unnoticed with invalid data. An exception, by contrast, can’t be “accidentally” ignored — either it’s explicitly handled, or the program visibly aborts, which surfaces errors earlier instead of letting them escalate opaquely later, at a completely different spot.

Important is the distinction between expectable errors (a file doesn’t exist, user input is invalid — situations every robust program should account for) and genuine programming errors (access outside array bounds, a null value where one should never be — signs of a bug in your own code). Some languages (Java) even distinguish this explicitly via “checked” (the compiler forces handling) and “unchecked” exceptions (optionally handleable, usually programming errors).

The finally block is especially important for cleanup work (closing a file, releasing a connection), because it’s guaranteed to run — whether everything went smoothly in the try block, an exception occurred, or even an early return sat in the middle of the try block. try-with-resources automates exactly this use case for resources that have to be closed.

See also: Errors, Multiple Exceptions, try-with-resources