Functions returning numeric or string codes for failure — `withdraw(amount)` returning -1 for insufficient funds — relying on callers to check and propagate.
Numeric or string error codes that callers must remember to check are replaced with exceptions that propagate by default.
Before the refactoring
function withdraw(amount) {if (amount > balance) return -1;balance -= amount;return 0;}
After the refactoring
function withdraw(amount) {if (amount > balance) throw new InsufficientFunds();balance -= amount;}
Forgetting to check silently swallows the error; the type system can't enforce the check; cleanup logic scatters across consumers.
Exceptions for predictable conditions misuse the mechanism — only convert codes that represent genuine, exceptional, unrecoverable failures.
Forgetting to check no longer silently swallows the error; the type system marks the failure path; cleanup happens via finally / try-with.
Using exceptions for predictable conditions — turning every error code into an exception introduces control flow via throws that callers must catch.