Commit fe33a72
committed
feat: Add exception handling demo for unchecked ArithmeticException with stack-trace printing
WHAT the code does:
- Defines `CheckedUncheckedException` with three helper methods: `fun1()`, `fun2()`, `fun3()` and `main()` which calls `fun3()`.
- `fun1()` performs `System.out.println(10/0);` inside a `try` block and catches `Exception`:
- Prints `e.getMessage()` and `e.printStackTrace()` when the division-by-zero occurs.
- `fun2()` → calls `fun1()`.
`fun3()` → calls `fun2()`.
`main()` → calls `fun3()`.
- At runtime this demonstrates an **unchecked exception** (ArithmeticException) being thrown and caught; the stack trace shows the call chain (`fun1` ← `fun2` ← `fun3` ← `main`).
WHY this matters:
- Distinguishes **checked** vs **unchecked** exceptions:
- Checked exceptions (e.g., `IOException`) must be declared or handled at compile time.
- Unchecked exceptions (e.g., `ArithmeticException`, `NullPointerException`) happen at runtime; the compiler does not force handling.
- Shows how exception handling changes program behavior from crashing to controlled error reporting.
- Demonstrates propagation: even though the exception originates in `fun1()`, the stack trace reveals the full call path, which is crucial for debugging.
- Important for production-quality code: deciding whether to catch, log, transform, or let the exception propagate is a key design decision.
HOW it works (step-by-step):
1. `main()` calls `fun3()`.
2. `fun3()` calls `fun2()`.
3. `fun2()` calls `fun1()`.
4. `fun1()` executes `10/0` which throws `ArithmeticException`.
5. The `catch (Exception e)` in `fun1()` handles the exception:
- `e.getMessage()` prints something like `/ by zero`.
- `e.printStackTrace()` prints the exception type and the call stack showing where it happened.
6. Program continues after the catch block (no crash because exception was handled).
TIPS, GOTCHAS & IMPROVEMENTS (production-ready and interview-smart):
- **Catch the specific exception** rather than `Exception`:
- Use `catch (ArithmeticException e)` so you only handle expected failures and don’t accidentally swallow other problems.
- **Prefer validation to exceptions** where applicable:
- If you're dividing by a variable divisor, check `if (divisor == 0)` and handle that case instead of relying on exceptions for control flow.
- **Logging vs printing**:
- Replace `e.printStackTrace()` with a proper logger (e.g., `Logger.error("Division failed", e)`) in real apps — it’s configurable and thread-safe.
- **Don’t swallow exceptions silently**:
- If a method cannot correctly handle the error, either rethrow it (`throw e;` or `throw new RuntimeException(e)`) or return an error result so the caller can decide.
- **Use finally / try-with-resources** for cleanup:
- When resources are involved (files, streams, DB connections) ensure they’re closed in `finally` or by try-with-resources.
- **Document intention**:
- If you intentionally catch an unchecked exception to keep the program running, add a comment explaining why (otherwise readers assume a bug).
- **Avoid infinite or deep recursion**:
- Your previous examples showed recursion issues (`fun3()` recursively calling itself). Always ensure termination conditions to avoid `StackOverflowError`.
- **Unit tests**:
- Add tests asserting expected behavior for exception and normal cases (use JUnit `assertThrows` for expected exceptions).
Suggested improved `fun1()` (example):
```java
static void fun1() {
try {
System.out.println(10 / 0);
} catch (ArithmeticException e) {
// handle the specific error
System.err.println("Division by zero: " + e.getMessage());
// use a logger in real code: logger.error("Arithmetic error in fun1", e);
// optionally rethrow if caller should handle it:
// throw e;
}
}
Example output (current program):
/ by zero
java.lang.ArithmeticException: / by zero
at CheckedUncheckedException.fun1(CheckedUncheckedException.java:4)
at CheckedUncheckedException.fun2(CheckedUncheckedException.java:9)
at CheckedUncheckedException.fun3(CheckedUncheckedException.java:13)
at CheckedUncheckedException.main(CheckedUncheckedException.java:17)
Use-cases / analogies:
• Defensive coding: validating user inputs (e.g., divisor) before performing operations prevents runtime exceptions.
• Server process: catching exceptions at the lower level and logging them prevents a whole service from crashing.
• Debugging: stack traces are like breadcrumbs showing the path the program took before it failed.
Short key: java-exceptions unchecked ArithmeticException catch-specific logging input-validation.
Signed-off-by: https://github.com/Someshdiwan <[email protected]>1 parent b1357da commit fe33a72
File tree
1 file changed
+10
-12
lines changed- Section18ExceptionHandling/src
1 file changed
+10
-12
lines changedLines changed: 10 additions & 12 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | | - | |
3 | | - | |
4 | | - | |
5 | | - | |
| 2 | + | |
| 3 | + | |
6 | 4 | | |
7 | 5 | | |
8 | | - | |
9 | | - | |
| 6 | + | |
| 7 | + | |
10 | 8 | | |
11 | 9 | | |
12 | 10 | | |
13 | 11 | | |
14 | | - | |
15 | | - | |
| 12 | + | |
| 13 | + | |
16 | 14 | | |
17 | 15 | | |
18 | | - | |
19 | | - | |
| 16 | + | |
| 17 | + | |
20 | 18 | | |
21 | 19 | | |
22 | | - | |
23 | | - | |
| 20 | + | |
| 21 | + | |
24 | 22 | | |
25 | 23 | | |
26 | 24 | | |
0 commit comments