This repository contains small, focused Java programs that demonstrate and explain Java's exception-handling mechanisms. The goal is to help beginners and intermediate learners understand checked vs unchecked exceptions, throw vs throws, try / catch / finally, exception propagation, custom exceptions, and common best practices. Each file is short and targeted so you can run, inspect, and learn quickly.
Files in this repo
CustomChecked.java— a simple checked custom exception (extendsException).CustomUnchecked.java— a runtime/unchecked custom exception (extendsRuntimeException).Program01.java— basictry-catch-finallyexample (ArithmeticException / basic handling).Program02.java— multi-catch / multiple catches / ordering and common pitfalls.Program03.java— nested try / rethrowing / propagation example.Throw.java— demonstrates usingthrowexplicitly to raise exceptions.Throws.java— demonstrates thethrowskeyword and exception propagation through method signatures.
Note: the code files are intentionally compact teaching examples. Read the "Deep explanations" section below to understand the intent and expected behavior of each program.
Assuming you have JDK installed and you're inside the repo directory with the .java files at root:
# compile all .java files
javac *.java
# run examples (pick one):
java Program01
java Program02
java Program03
java Throw
java ThrowsIf the examples are in a package, compile and run with package paths. If you see compile errors about checked exceptions, that is intentional in some examples — they show what the compiler enforces.
- Checked exceptions are subclasses of
Exception(exceptRuntimeException). The compiler forces callers to handle them (either withtry-catchorthrows). Good for recoverable conditions (I/O errors, database exceptions). - Unchecked exceptions are subclasses of
RuntimeException(andError). They represent programming errors (null pointer, arithmetic, index out-of-bounds) and the compiler does not force handling.
Files: CustomChecked.java demonstrates declaring a checked exception class. CustomUnchecked.java demonstrates a runtime exception.
When to create custom exceptions:
- Use custom checked exceptions when you want the caller to be forced to handle or explicitly propagate an expected, recoverable condition.
- Use custom unchecked exceptions when a condition indicates a programmer error or unrecoverable state (invalid arguments, illegal state).
Implementation notes to check in CustomChecked.java / CustomUnchecked.java:
- Provide the common constructors: default,
String message,String message, Throwable cause, andThrowable cause— this preserves stack traces and chaining.
trywraps code that might throw;catchhandles specific exception types.finallyruns whether or not an exception occurred (unless the JVM exits).- The order of
catchblocks matters — catch more specific exceptions first, then broader ones. From Java 7 on you can use multi-catch (catch (A|B ex)), but avoid combining exceptions if you need to call exception-specific methods.
File: Program01.java shows a simple try-catch-finally that handles ArithmeticException and prints a useful message and stack trace.
Common mistakes:
- Catching
Exceptiontoo early — hides specific problems. - Empty catch blocks (
catch (Exception e) {}) — this swallows errors and makes debugging hard.
throwis used to raise an exception instance in code:throw new IllegalArgumentException("bad").throwsgoes on a method declaration to say the method may propagate (not handle) checked exceptions:void foo() throws IOException { ... }.
Files: Throw.java demonstrates throw. Throws.java demonstrates throws in a method signature and shows propagation up the call stack.
Points to observe:
- You cannot
throwa checked exception without declaringthrowsin the method signature or catching it locally. - You can throw unchecked exceptions anywhere.
When an exception is not caught in a method, it propagates to the caller. Sometimes you want to catch, do cleanup or logging, and then rethrow the same or a new exception (exception translation).
File: Program03.java shows nested try-catch where inner code throws an exception, an inner catch logs something and rethrows (or wraps) it. Look for throw e; or throw new MyCheckedException("context", e);.
Best practice: When wrapping an exception, include the original as the cause (new RuntimeException("msg", original)) so stack traces remain informative.
When using resources (I/O streams, DB connections), prefer try-with-resources which automatically closes resources and correctly handles suppressed exceptions. Suppressed exceptions are those thrown while closing resources — they are attached to the primary exception and can be viewed via Throwable.getSuppressed().
Not every example in this repo uses try-with-resources, but it's an important pattern to prefer for real code that deals with
AutoCloseableresources.
- Declares
public class CustomChecked extends Exception. - Includes standard constructors.
- Purpose: teach creation and usage of a checked exception. Example usage: a method might
throw new CustomChecked("...reason...")and the caller musttry-catchorthrowit further.
- Declares
public class CustomUnchecked extends RuntimeException. - Includes standard constructors.
- Purpose: show an exception type that does not need
throwsand is used for runtime errors.
- Simple arithmetic example (divide by zero) inside
try. catch (ArithmeticException e)prints user-friendly message ande.printStackTrace().finallyblock prints a message to show it always runs.
Expected output (example)
Attempting division...
Caught ArithmeticException: / by zero
Finally block executed
Program ended
- Example of multiple catch blocks and (possibly) a multi-catch example.
- Shows order sensitivity and handling different exception types (e.g.,
NumberFormatException,ArrayIndexOutOfBoundsException). - Demonstrates
catch (IOException | SQLException e)style when appropriate.
- Demonstrates nested try blocks and rethrowing (or wrapping) an exception for higher-level context.
- Shows how a top-level caller might handle the rethrown exception.
- Demonstrates
throw new IllegalArgumentException(...)and/orthrow new CustomChecked(...)with appropriate method signature if a checked exception is thrown. - Purpose: show explicit raising of exceptions when validating arguments or state.
- Demonstrates method signatures with
throws CustomCheckedorthrows Exceptionand shows how themainmethod either handles or declares exception. - Purpose: teach propagation and the compiler enforcement for checked exceptions.
Custom checked exception skeleton
public class CustomChecked extends Exception {
public CustomChecked() { super(); }
public CustomChecked(String message) { super(message); }
public CustomChecked(String message, Throwable cause) { super(message, cause); }
public CustomChecked(Throwable cause) { super(cause); }
}Throwing a checked exception (must declare or catch)
public void risky() throws CustomChecked {
if (/* bad condition */) {
throw new CustomChecked("something went wrong");
}
}Rethrowing with context
try {
risky();
} catch (CustomChecked e) {
// add context and rethrow
throw new RuntimeException("High-level operation failed", e);
}- Prefer specific catches: catching
Exceptionhides bugs; catch the specific exception and handle it. - Don't swallow exceptions: never leave empty
catchblocks — at least log or rethrow. - Wrap with context: when rethrowing, wrap the original exception to keep the cause chain:
new MyException(msg, cause). - Use unchecked for programmer errors: invalid arguments or illegal states should typically be unchecked.
- Use checked for recoverable failures: I/O, network, and user-correctable issues.
- Try-with-resources for
AutoCloseableresources to prevent resource leaks and get correct suppressed-exception handling. - Log the stack trace when diagnosing in development; in production use structured logging and redact sensitive info.
- Document the exception behavior in method javadocs (
@throws) so callers know what to expect.
Q: When should I create a custom exception?
A: When you need to convey domain-specific error information (e.g., InsufficientBalanceException) and either force callers to handle it (checked) or convey a clear runtime error (unchecked).
Q: Is it ok to always throw RuntimeException for convenience?
A: No. Overusing unchecked exceptions makes it easy to ignore error handling and can make client code brittle. Use the right tool for the job.
Q: How to preserve the original stack trace?
A: Use exception chaining: new Exception("message", original) so original becomes the cause.
unreported exception CustomChecked; must be caught or declared to be thrown— fix by either wrapping the call intry-catchor declaringthrows CustomCheckedon the method.incompatible typesafter multi-catch — remember in multi-catch you cannot call exception-specific methods without casting because the compile-time type is the union type.
If you want to improve the repo:
- Add more examples (I/O exceptions, file handling with try-with-resources,
InterruptedExceptionhandling for threads, etc.). - Add unit tests that intentionally provoke exceptions so students can see stack traces and suppressed exceptions in action.
- Add a
docs/folder with diagrams that show stack traces and propagation flows.
Please open a PR with clear explanations and example outputs. .
Happy deep-diving — run the examples, step through with a debugger, and inspect stack traces. If you want, I can also convert this README into a polished GitHub-flavored README with badges and screenshots.
Author: Parthrajsinh1 (project owner)