1. Exceptions should only be used for exceptional circumstances and should not drive normal program control flow.
2. Checked exceptions should be used if they allow the caller to recover, while unchecked exceptions should be used if the caller cannot recover.
3. Higher layers should catch and rethrow exceptions from lower layers in terms of the higher-level abstraction.