What is the difference between a checked and an unchecked exception in Java, and how does the compiler treat them?
The dividing line is whether the exception extends RuntimeException. If it does, it is unchecked; if it extends Exception but not RuntimeException, it is checked.
The compiler treats them differently. When a method may throw a checked exception, every call site must either catch it or declare it in its own throws clause. The compiler enforces this, and the effect is that you cannot call a method that can fail without explicitly deciding what to do about the failure. Unchecked exceptions need no such declaration — they propagate automatically, and the compiler lets you ignore them.
The rationale for the split is about who can act on the failure. A checked exception represents a condition outside the program's control that a caller can plausibly recover from: a file that might not exist, a network that might time out, a row that might violate a constraint. Requiring the caller to decide forces that decision to be made. An unchecked exception represents a programming error — a null reference, a bad argument, an index out of range — where the only sensible response is to fix the code, so forcing a catch clause on every caller would be noise that hides the bug rather than surfacing it.
The practical consequence people trip over is that unchecked exceptions can propagate out of any method without being declared, so a method's throws clause tells you nothing about every failure it might produce. Only the checked ones are part of its published contract. That is why libraries tend to throw unchecked exceptions for programming errors and checked ones for recoverable I/O conditions, and why the throws clause of a well-designed API is short and meaningful.