A checked exception is an exception that the compiler forces us to either catch or declare with throws, whereas an unchecked exception, which is a RuntimeException, an Error or one of their subclasses, compiles without either. Both kinds are thrown at run time, so the difference between checked and unchecked exceptions in Java is only what the compiler checks before the code runs.
We use checked exceptions for failures outside our code that a caller can react to, such as a missing file or a dropped network connection. Unchecked exceptions report bugs and broken assumptions, such as a null argument or a bad index, and errors report JVM problems such as running out of memory.
The following example triggers one exception of each kind while importing a playlist.
String error = "none";
try {
String text = Files.readString(Path.of("missing.m3u")); // checked: needs try or throws
} catch (IOException e) {
error = e.getClass().getSimpleName();
}
String caught = error; // "NoSuchFileException"
int seconds = Integer.parseInt("3:45"); // NumberFormatException, compiles without try
Notice that the compiler refuses the readString() call without the try block, while the parseInt() call compiles and fails only when it runs. We start from the exception class hierarchy, look at each kind with its compiler rules, compare them, and finish with a map of our guides for specific exceptions.
1. The Exception Hierarchy in Java
Every exception in Java is an object of a class that extends Throwable. The class tree under Throwable decides whether an exception is checked, and the rule in JLS 11.1.1 is short. RuntimeException, Error and their subclasses are unchecked, and every other subclass of Throwable is checked.

The four classes at the top of the tree carry different meanings, so it helps to know what each one stands for before we write a catch block.
| Class | Kind | What it reports | Examples |
|---|---|---|---|
| Throwable | Checked | The root type; we never throw or catch it in app code | Exception, Error |
| Exception | Checked | Conditions an app can expect and handle | IOException, SQLException, InterruptedException |
| RuntimeException | Unchecked | Programming errors and invalid arguments or state | NullPointerException, IllegalArgumentException, ArithmeticException |
| Error | Unchecked | Serious JVM problems that an app does not try to fix | OutOfMemoryError, StackOverflowError, NoClassDefFoundError |
A common surprise is that RuntimeException extends Exception, so a catch (Exception e) block also catches every runtime exception. The JLS still exempts RuntimeException and its subclasses from the compiler check, because forcing try blocks around every array access or division would add code without making programs more correct.
2. Checked Exceptions and the Catch-or-Declare Rule
A checked exception describes a failure that can happen even when our code is correct, because it depends on something outside the program. Files get deleted, servers go down and users upload broken data. The compiler wants every caller to make a decision about such a failure, so a method that can throw a checked exception must either catch it or list it in its throws clause.
Say a music app lets users import playlists from .m3u files. The file may be gone, unreadable or on a disconnected drive, and the app should show a message instead of crashing. That is the kind of failure checked exceptions were designed for.
The following example is a method that reads the playlist file. The method Files.readString() declares throws IOException, and our method neither catches nor declares it.
// does not compile: unreported exception IOException
static String loadPlaylist(Path file) {
return Files.readString(file);
}
The compiler stops with this message on JDK 25.
Playlist.java:4: error: unreported exception IOException; must be caught or declared to be thrown
return Files.readString(file);
^
1 error
2.1. Handling a Checked Exception With try-catch
We catch the exception when the current method knows what to do about it. A method that returns an empty playlist for a missing file can handle the failure itself, so the caller never sees the exception.
static List<String> loadOrEmpty(Path file) {
try {
return Files.readAllLines(file);
} catch (IOException e) {
return List.of(); // missing or unreadable file
}
}
List<String> tracks = loadOrEmpty(Path.of("missing.m3u")); // []
The try-catch-finally guide covers multiple catch blocks, finally and the order in which they run.
2.2. Declaring a Checked Exception With throws
We declare the exception when only the caller can decide. A low-level reader has no idea whether the UI should retry, ask for another file or give up, so it passes the exception on with throws.
static List<String> loadTracks(Path file) throws IOException {
return Files.readAllLines(file);
}
List<String> loaded = loadTracks(Path.of("missing.m3u")); // NoSuchFileException
Every caller of loadTracks() faces the same rule again, until some method catches the exception. The difference between the two keywords is the topic of throw vs throws in Java.
The compiler checks only that a checked exception is handled or declared; it never checks that the handling makes sense. An empty catch block satisfies the compiler and hides the failure, so we log, rethrow or return a clear fallback value instead.
Most checked exceptions we meet in the JDK belong to a few families.
- IOException and its subclasses, such as FileNotFoundException, NoSuchFileException and SocketTimeoutException.
- SQLException from JDBC calls.
- InterruptedException from blocking calls such as Thread.sleep() and BlockingQueue.take(), explained in our InterruptedException guide.
- ReflectiveOperationException subclasses, such as ClassNotFoundException and NoSuchMethodException.
- GeneralSecurityException subclasses, such as InvalidKeyException and NoSuchAlgorithmException.
3. Unchecked Exceptions
An unchecked exception most often means the code itself is wrong. A method received a null it did not expect, an index went past the end of a list, or an object was used in the wrong state. The compiler does not force us to catch or declare these exceptions, because the fix is to correct the code, not to wrap every line in a try block.
The following example shows three runtime exceptions that compile without any handling.
List<String> queue = List.of("intro", "chorus");
String third = queue.get(2); // IndexOutOfBoundsException
String title = null;
int length = title.length(); // NullPointerException
Object track = "intro";
Integer id = (Integer) track; // ClassCastException
Since Java 15, helpful NullPointerException messages are on by default and name the call or variable that was null, which makes the bug in the second line quick to find. The NullPointerException guide covers ways to avoid it.
3.1. Throwing Unchecked Exceptions for Invalid Input
We also throw unchecked exceptions ourselves when a caller breaks a method contract. The JDK has standard classes for this purpose, so a method fails fast with a clear message instead of storing bad data. For example, a playlist must not accept a track with a negative duration.
record Track(String title, int seconds) {
Track {
Objects.requireNonNull(title, "title");
if (seconds < 0) {
throw new IllegalArgumentException("seconds must be >= 0: " + seconds);
}
}
}
Track ok = new Track("intro", 225); // Track[title=intro, seconds=225]
Track bad = new Track("outro", -5); // IllegalArgumentException: seconds must be >= 0: -5
The IllegalArgumentException article lists when to prefer it over IllegalStateException and NullPointerException.
3.2. Errors
Errors are unchecked too, but they come from the JVM, not from our logic. An OutOfMemoryError means the heap is full, and a StackOverflowError means a recursion went too deep. App code rarely catches them, because the JVM may be in a state where no recovery is reliable. Linkage errors, such as NoSuchMethodError, point to a mismatch between the classes we compiled against and the ones on the runtime classpath.
4. Checked vs Unchecked Exceptions Compared
The two kinds differ in what the compiler enforces and in what they tell the reader of the code. The table sums up the differences that matter when we write or call a method.
| Aspect | Checked exceptions | Unchecked exceptions |
|---|---|---|
| Classes | Throwable and its subclasses, except the unchecked ones | RuntimeException, Error and their subclasses |
| Compiler rule | Must be caught or declared with throws | No rule; catching or declaring is optional |
| When thrown | At run time | At run time |
| Typical cause | Conditions outside the program, such as files, network, databases | Bugs, invalid arguments or state, JVM problems |
| Caller can recover? | Often, by retrying or using a fallback | Rarely; the code needs a fix |
| Examples | IOException, SQLException, InterruptedException | NullPointerException, IllegalArgumentException, OutOfMemoryError |
| In lambdas | Not allowed by Function, Supplier and the other standard interfaces | Allowed anywhere |
The last row causes daily friction. The functional interfaces in java.util.function declare no checked exceptions, so a lambda that calls Files.readString() inside map() does not compile. The common fixes are wrapping the exception or extracting a helper method, as shown in our guide on handling checked exceptions in streams.
5. Choosing Between Checked and Unchecked for Our Own Exceptions
When we create our own exception class, we pick the kind by choosing the superclass. The guideline from the Oracle Java Tutorials still holds. If a client can reasonably be expected to recover from an exception, we make it a checked exception; if a client cannot do anything to recover, we make it unchecked.
In practice, many teams and frameworks lean toward unchecked exceptions. Spring translates SQLException into unchecked DataAccessException subclasses, and the JDK added UncheckedIOException in Java 8 so that stream code can carry an IOException. Checked exceptions cost a throws clause on every method between the thrower and the handler, which is worth it only when callers do something useful with the failure.
The following example wraps a checked exception into an unchecked one at the boundary of a stream pipeline. The original exception stays attached as the cause, so the stack trace keeps the real reason.
static String readQuietly(Path file) {
try {
return Files.readString(file);
} catch (IOException e) {
throw new UncheckedIOException("Cannot read " + file, e);
}
}
List<String> names = List.of("a.m3u", "b.m3u");
List<String> files = names.stream().map(Path::of).map(file -> readQuietly(file)).toList(); // UncheckedIOException: Cannot read a.m3u
Our post on custom exceptions in Java shows how to design a small hierarchy of app exceptions, and the exception handling best practices article collects the general rules.
6. Synchronous and Asynchronous Exceptions
Checked and unchecked describe what the compiler enforces. A second, rarely needed split describes where an exception can appear. Most exceptions are synchronous, which means the thread causes them itself at a point in the code that can throw, such as a division, a method call or a throw statement.
An asynchronous exception can appear at any point in the program. In Java 25, the JLS lists only one source, which is an internal error or resource limit inside the JVM, and the exception is a VirtualMachineError such as OutOfMemoryError or StackOverflowError. Those two errors can also be synchronous, for example when a large array allocation fails at a known line.
Older tutorials name Thread.stop() as a source of asynchronous exceptions. Since Java 20, Thread.stop() throws UnsupportedOperationException instead of stopping the thread, and ThreadGroup.stop() no longer exists in Java 25.
Thread worker = new Thread(() -> { });
worker.stop(); // UnsupportedOperationException
Pressing Ctrl+C is not an exception either. The JVM receives a signal from the operating system and starts its shutdown sequence, which runs shutdown hooks registered with Runtime.addShutdownHook(); no catch block sees it. To stop a thread cooperatively, we call interrupt() and let the thread check its interrupted flag.
7. Exception Guides Grouped by Task
Once the checked and unchecked rules are clear, most questions are about one specific exception or error message. Our guides cover them by task, and each one starts with the cause and the fix.
| Task | Guides |
|---|---|
| Write handling code | Suppressed exceptions and try-with-resources, try-with-resources statement |
| Fix common runtime exceptions | IllegalStateException: No match found, UnsupportedOperationException on lists, ArrayStoreException, IllegalMonitorStateException |
| Handle exceptions in threads | UncaughtExceptionHandler |
| Fix class version and linkage errors | Class file has wrong version 61.0, Unsupported class file major version, IncompatibleClassChangeError: Implementing class |
| Fix build path and dependency errors | HttpServlet not found on the build path, ClassNotFoundException: FileItemFactory, Taglib definition not consistent with specification version |
| Fix test and benchmark tooling | JMH Unable to find the resource /META-INF/BenchmarkList, This version of ChromeDriver only supports Chrome version |
| Fix security and TLS exceptions | InvalidKeyException: Parameters missing, SSLHandshakeException |
For the language basics behind these posts, such as classes, methods and control flow, the Java tutorial lists every topic in reading order.
8. Checked and Unchecked Exception FAQs
Most classification questions name one exception class, so each answer gives the verdict first, followed by the superclass that decides it.
8.1. Is IOException checked or unchecked?
Checked. IOException extends Exception and not RuntimeException, so every method that can throw it must catch it or declare it. Its unchecked companion for lambdas and streams is UncheckedIOException.
8.2. Is NullPointerException checked or unchecked?
Unchecked. NullPointerException extends RuntimeException, so the compiler never asks us to handle it. It points to a bug, and the fix is a null check, Objects.requireNonNull() or Optional, not a catch block.
8.3. Are checked exceptions thrown at compile time?
No. Every exception is thrown while the program runs. The compiler only verifies that checked exceptions are caught or declared, which is why some books call them compile-time checked exceptions.
8.4. Can we catch an Error in Java?
Yes, the syntax allows it, because Error is a Throwable. App code catches errors only in narrow cases, such as a top-level handler that logs a StackOverflowError from a recursive parser before failing the request.
8.5. Why can we catch Exception when the try block throws nothing?
The compiler rejects a catch for a checked exception that the try block cannot throw, such as catch (IOException e) around plain arithmetic. JLS 11.2.3 makes an exception for Exception and Throwable, because they also catch unchecked exceptions that any code can throw.
Order.java:10: error: exception IOException is never thrown in body of corresponding try statement
8.6. Is SQLException checked?
Yes. SQLException is a checked exception, so plain JDBC code needs try blocks or throws clauses. Frameworks such as Spring JDBC and JPA providers wrap it in unchecked exceptions.
9. Conclusion
Checked exceptions are Throwable subclasses outside RuntimeException and Error, and the compiler makes us catch or declare them. They fit failures that callers can handle, such as missing files and network errors.
Unchecked exceptions report bugs, invalid input and JVM problems. We fix their cause instead of catching them, throw standard ones such as IllegalArgumentException for broken contracts, and wrap checked exceptions in unchecked ones where a throws clause does not fit, such as inside lambdas.
10. References
- JLS 25, Chapter 11. Exceptions
- Throwable (Java SE 25 API)
- RuntimeException (Java SE 25 API)
- Unchecked Exceptions, The Controversy (Java Tutorials)
- UncheckedIOException (Java SE 25 API)
Happy Learning !!
Hi please add some info about error class and difference between it and exception.
https://docs.oracle.com/javase/8/docs/api/java/lang/RuntimeException.html
Any class that is a subsclass (but not a subsclass of RuntimeException) is a checked exception.
As i heard that checked exceptions should not consider at all. Most languages will not use them too. But one can always throw a subclass of Runtime Exception i.e, unchecked exception according to my thoughts checked exceptions are useful as they are used when someone wants to force the user of their API to think how to carry on the exceptional situation. And people hate checked exceptions because they are overused in the Java platform.
The main difference with Checked and UnChecked Exception is that checked Exception requires mandatory try catch or try finally block but unchecked Exception don’t. Another difference between Checked and UnChecked Exception is in where to use them.
Checked Exception should be used if you know how to recover from Exception while Unchecked Exception should be used for programming errors.
And i have a question for you regarding this article, can you please clarify me. My question is that If you can handle checked exception, then why not each exception is checked exception? why java have a concept of unchecked exception? Thanks for your detailed blog…
Because an unchecked exception cannot be detected at compilation time e.g if u try to access an index of array beyond range it can only be detected only when the program runs not before that.
The exceptions which are checked by compiler for smooth execution of the program at run time are called checked exception. keep blogging.
i am assumed that nullpointerexception is checked exception what happened?
Absolutely no idea, what you are asking?
Is it good idea to handle unchecked exception? what best practices say?
Hi Lokesh,
Checked exceptions are the subclass of Exception and Unchecked exception are the subclass of RuntimeException(RuntimeException is a subclass of Exception again).
Suppose you have two custom exception classes MyException1.java(This extends RuntimeException) and MyException2.java(Extends Exception class).
Suppose a method in any class throws MyException1 exception. While calling this method in any other places,it is not mandatory to catch the exception.But if the method throws MyException2 exception you are forced to catch the exception.(Either surround with try/catch or throws the exception).
My question is when your custom exception class extends RuntimeException why it is not treated as a checked exception,? even tough RuntimeException the Exception class?
Regards
Partha
typo in my last line. even tough RuntimeException extends the Exception class.
I already mentioned: “Here, the strange thing is that RuntimeException is itself subclass of Exception i.e. all Unchecked exception classes should have been checked exceptions implicitly, BUT they are not. I am confuse. Any thoughts??”
I am really clueless about this design choice, JDK designers followed…
As per my thought, it is just an indication to the JVM, so it works accordingly. from the Java DOC, RuntimeException is Unchecked and Exception is Checked. So when our exception class extends the RuntimeException , it will be treated as Unchecked exception by the JVM and Exception will be treated as Checked exception.
Not sure about this but this is my thought.
Thanks for putting your thoughts. Can’t validate them.. :)
Hi,
Would like to know how compiler comes to know that a particular piece of code would result into a CheckedException. Meaning, if we use FILE IO or DB connection related utilities and don’t declare or handle them, then its a compile time error. In a way we can say that compiler is monitoring each and every line of code that we are introducing into the application but I am not sure how it understands and forces us to handle CheckedExceptions. Please suggest.
Actually method you use in your code have throws clause in their definition. Compiler read them. e.g. DriverManager.getConnection() is used to get connection from database. It declares throwing SQLException in ins definition. Any caller method must handle this exception. Compiler just enforce it.
https://github.com/openjdk/jdk/blob/master/src/java.sql/share/classes/java/sql/DriverManager.java
Nice explanation. But I think Checked exceptions are a thing of past and do not have much significance as I have written the reasons here
Its very informative and absolute answer. But can you explain how to create user defined exception.
Hello Lokesh. Thanks for this post and very well explained. could you please tell me the difference between
Throws and Throw ? as i am little but confusing about these two
`throws` declares the exceptions the method throws, and is used in the method signature.
`throw` is used to throw an exception
“`
void foo() throws Exception1 {
…
throw new Exception1(“Something bad happened”);
…
}
“`
Its very good job Sir,
thanks for all that.:)