Types of Exceptions in Java – Explained with Examples
Java groups its exceptions into a few families, and knowing them tells you a lot: whether the compiler will force you to handle a problem, whether it usually means a bug in your code, and whether recovery is possible at all. This tutorial explains the three main categories, checked exceptions, unchecked exceptions and errors, shows the most common built-in exceptions in action, and introduces user-defined exceptions.
1. The Main Categories
Throwable
├─ Error (unchecked) serious JVM / environment problems
└─ Exception
├─ checked exceptions IOException, SQLException, InterruptedException ...
└─ RuntimeException (unchecked) NullPointerException, ArithmeticException ...
| Category | Extends | Must be caught or declared? | Usually means |
|---|---|---|---|
| Checked exception | Exception (not RuntimeException) | Yes, enforced by the compiler | An expected problem outside your control (file, network, database) |
| Unchecked exception | RuntimeException | No | A programming bug or invalid input |
| Error | Error | No | A serious problem the application usually cannot fix |
You can also divide exceptions into built-in exceptions provided by Java and user-defined (custom) exceptions you create yourself.
2. Unchecked Exceptions (Runtime Exceptions)
Unchecked exceptions are subclasses of RuntimeException. The compiler does not force you to handle them because they usually signal mistakes that should be fixed in the code, not caught. Here are the most common ones, each triggered on purpose:
import java.util.List;
public class CommonUnchecked {
static String missing = null;
static void attempt(String label, Runnable action) {
try {
action.run();
} catch (RuntimeException e) {
System.out.printf("%-28s -> %s: %s%n", label, e.getClass().getSimpleName(), shorten(e.getMessage()));
}
}
static String shorten(String msg) { // keep long JDK messages readable
return msg != null && msg.contains(" (") ? msg.substring(0, msg.indexOf(" (")) : msg;
}
public static void main(String[] args) {
Object number = 42;
int[] arr = new int[2];
attempt("missing.length()", () -> missing.length());
attempt("10 / 0", () -> System.out.println(10 / 0));
attempt("arr[5]", () -> System.out.println(arr[5]));
attempt("\"abc\".charAt(7)", () -> "abc".charAt(7));
attempt("Integer.parseInt(\"12a\")", () -> Integer.parseInt("12a"));
attempt("(String) number", () -> System.out.println((String) number));
attempt("List.of(1).add(2)", () -> List.of(1).add(2));
attempt("new int[-1]", () -> System.out.println(new int[-1].length));
}
}
missing.length() -> NullPointerException: Cannot invoke "String.length()" because "CommonUnchecked.missing" is null
10 / 0 -> ArithmeticException: / by zero
arr[5] -> ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 2
"abc".charAt(7) -> StringIndexOutOfBoundsException: Index 7 out of bounds for length 3
Integer.parseInt("12a") -> NumberFormatException: For input string: "12a"
(String) number -> ClassCastException: class java.lang.Integer cannot be cast to class java.lang.String
List.of(1).add(2) -> UnsupportedOperationException: null
new int[-1] -> NegativeArraySizeException: -1
| Exception | Cause | How to avoid it |
|---|---|---|
NullPointerException | Using a null reference | Initialise variables, check for null, use Optional |
ArithmeticException | Integer division by zero | Check the divisor first |
ArrayIndexOutOfBoundsException | Index outside 0…length-1 | Loop with i < arr.length |
StringIndexOutOfBoundsException | Invalid index into a string | Check length() first |
NumberFormatException | Parsing invalid numeric text | Validate input, catch around parsing |
ClassCastException | Invalid cast | Use instanceof pattern matching |
UnsupportedOperationException | Modifying an unmodifiable collection | Copy into a modifiable collection |
IllegalArgumentException | A method received an invalid argument | Validate arguments before calling |
IllegalStateException | Method called at the wrong time | Follow the object's life cycle |
ConcurrentModificationException | Changing a collection while iterating | Use removeIf() or an iterator |
3. Checked Exceptions
Checked exceptions represent problems that can happen even in correct code: a file may be missing, a server may be down, a thread may be interrupted. Java requires every method that might throw one to either catch it or declare it with throws; otherwise the code does not compile.
import java.io.FileReader;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.time.LocalDate;
import java.time.format.DateTimeParseException;
public class CommonChecked {
public static void main(String[] args) {
// Checked: the compiler forces us to handle (or declare) these
try (FileReader reader = new FileReader("no-such-file.txt")) {
System.out.println("opened");
} catch (IOException e) {
System.out.println("IOException family -> " + e.getClass().getSimpleName() + ": " + e.getMessage());
}
try {
new URI("http://bad host/");
} catch (URISyntaxException e) {
System.out.println("URISyntaxException -> " + e.getMessage());
}
try {
Thread.sleep(10);
System.out.println("InterruptedException must be handled around Thread.sleep()");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// Unchecked: handling is optional
try {
LocalDate.parse("2026-13-40");
} catch (DateTimeParseException e) {
System.out.println("DateTimeParseException (unchecked) -> " + e.getMessage());
}
}
}
IOException family -> FileNotFoundException: no-such-file.txt (No such file or directory) URISyntaxException -> Illegal character in authority at index 10: http://bad host/ InterruptedException must be handled around Thread.sleep() DateTimeParseException (unchecked) -> Text '2026-13-40' could not be parsed: Invalid value for MonthOfYear (valid values 1 - 12): 13
| Checked exception | Typical source |
|---|---|
IOException, FileNotFoundException | Files, streams, sockets |
SQLException | JDBC database access |
InterruptedException | Thread.sleep(), join(), blocking queues |
ClassNotFoundException | Loading a class by name |
URISyntaxException, MalformedURLException | Building URIs and URLs |
CloneNotSupportedException | Object.clone() |
Note that DateTimeParseException is unchecked even though it is about input; newer APIs often prefer unchecked exceptions. Learn more in Checked vs Unchecked Exceptions.
4. Errors
Errors are thrown by the JVM when something is seriously wrong with the runtime environment. Applications normally should not catch them, because there is little they can do to recover:
public class ErrorExamples {
static int depth = 0;
static void recurse() { depth++; recurse(); }
public static void main(String[] args) {
try {
recurse(); // no base case
} catch (StackOverflowError e) {
System.out.println("StackOverflowError after many nested calls (an Error, not an Exception)");
}
System.out.println("StackOverflowError is an Exception? " + (Exception.class.isAssignableFrom(StackOverflowError.class)));
System.out.println("OutOfMemoryError is a Throwable? " + (Throwable.class.isAssignableFrom(OutOfMemoryError.class)));
}
}
StackOverflowError after many nested calls (an Error, not an Exception) StackOverflowError is an Exception? false OutOfMemoryError is a Throwable? true
OutOfMemoryError: the heap is full.StackOverflowError: too many nested method calls, usually endless recursion.NoClassDefFoundError: a class available at compile time is missing at runtime.ExceptionInInitializerError: a static initializer threw an exception.AssertionError: anassertstatement failed.
See Error vs Exception.
5. User-Defined (Custom) Exceptions
When built-in exceptions do not describe a problem precisely, create your own by extending Exception (checked) or RuntimeException (unchecked):
public class InsufficientBalanceException extends RuntimeException {
public InsufficientBalanceException(double needed, double available) {
super("Need " + needed + " but only " + available + " is available");
}
}
A full guide is in Custom Exception in Java.
6. Which Type Should Your Code Throw?
- Invalid arguments:
IllegalArgumentExceptionorNullPointerException(viaObjects.requireNonNull). - Calling a method at the wrong time:
IllegalStateException. - Unsupported operations:
UnsupportedOperationException. - Domain-specific problems: a custom exception with a clear name.
- Recoverable external failures that callers must handle: a checked exception (or a well-documented unchecked one).
- Never throw
Errortypes yourself, exceptAssertionErrorfor impossible situations.
7. Summary
- Java exceptions are checked exceptions, unchecked (runtime) exceptions, and errors.
- Checked exceptions must be caught or declared; unchecked exceptions and errors need not be.
- Unchecked exceptions usually reveal bugs; checked exceptions represent expected external failures.
- Errors indicate serious JVM problems and are normally not caught.
- Create custom exceptions for application-specific problems.
Related Tutorials
Frequently Asked Questions (FAQ)
Q1. What are the types of exceptions in Java?
Checked exceptions, unchecked (runtime) exceptions and errors. They can also be classified as built-in exceptions and user-defined (custom) exceptions.
Q2. What is a checked exception?
An exception that the compiler checks: any method that can throw it must catch it or declare it with throws. Examples are IOException and SQLException.
Q3. What is an unchecked exception?
A subclass of RuntimeException, such as NullPointerException, which the compiler does not require you to catch or declare.
Q4. Are errors checked or unchecked?
Unchecked. Classes extending Error never need to be caught or declared.
Q5. Is NullPointerException checked or unchecked?
Unchecked. It extends RuntimeException.
Q6. Is IOException checked or unchecked?
Checked. Code that can throw it must handle it with try-catch or declare it with throws IOException.
Q7. Is InterruptedException checked?
Yes. When catching it, restore the interrupt flag with Thread.currentThread().interrupt() unless you are ending the thread.
Q8. What is the most common exception in Java?
NullPointerException is famously the most frequent. Since Java 14, its message tells you exactly which reference was null.
Q9. What is a runtime exception?
Another name for an unchecked exception: an instance of RuntimeException or one of its subclasses, usually caused by a bug or invalid input.
Q10. What is the difference between ClassNotFoundException and NoClassDefFoundError?
ClassNotFoundException is a checked exception thrown when code explicitly loads a class by name and it is not found. NoClassDefFoundError is an error thrown when a class that existed at compile time cannot be found at runtime.
Q11. What is NumberFormatException a subclass of?
IllegalArgumentException, which extends RuntimeException, so it is unchecked.
Q12. Can I create my own exception types?
Yes. Extend Exception for a checked exception or RuntimeException for an unchecked one, and give it meaningful constructors.
Q13. Should I catch Error?
Generally no. Errors like OutOfMemoryError indicate the JVM is in trouble. Top-level code may log them before shutting down, but should not try to continue as normal.
Q14. Why is ArithmeticException unchecked?
Because it results from a programming error (dividing by zero) that should be prevented by checking values, not handled after the fact.
Q15. Which exception occurs when casting fails?
ClassCastException. Avoid it by checking with instanceof before casting, or by using pattern matching (if (obj instanceof String s)).
Q16. What is UnsupportedOperationException?
An unchecked exception thrown when an operation is not supported, most often when modifying an immutable collection such as one created by List.of().
Q17. What is the parent class of all checked exceptions?
Exception. Every subclass of Exception that is not a subclass of RuntimeException is checked.
Q18. Is SQLException checked?
Yes. JDBC methods declare it, so callers must handle or declare it. Frameworks such as Spring translate it into unchecked exceptions.
Q19. What is StackOverflowError?
An error thrown when a thread's call stack is exhausted, almost always because of recursion without a proper base case.
Q20. Which exceptions should I throw for invalid method arguments?
IllegalArgumentException for bad values, NullPointerException (usually via Objects.requireNonNull()) for unexpected nulls, and IndexOutOfBoundsException for invalid indexes.