What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.
java.lang.RuntimeException is a Java class whose subclasses are unchecked exceptions: the compiler does not require a method to catch them or declare them with throws. They can signal invalid input, an object in the wrong state, a violated assumption, or another problem detected while code runs. Unchecked does not mean harmless or unimportant; it describes a compiler rule, not how serious the failure is.
Where RuntimeException fits in Java
The name can refer either to the specific class RuntimeException or, in ordinary usage, to an exception in its subclass hierarchy. For example, NullPointerException and IllegalArgumentException are runtime exceptions even though their class names do not contain “Runtime.”
java.lang.Object
└── java.lang.Throwable
├── java.lang.Error
└── java.lang.Exception
├── checked exception classes, such as IOException
└── java.lang.RuntimeException
└── unchecked exception subclasses
RuntimeException extends Exception; it is not a special crash mode or a separate runtime system. Error is a separate branch under Throwable. The Java SE 26 API reference documents the class and its constructors, while Chapter 11 of the Java Language Specification defines the exception categories and compile-time rules.
Why it is unchecked
Java requires checked exceptions to be caught or declared in a method’s throws clause. Runtime exceptions and their subclasses are exempt from that requirement. Many can arise from normal expressions and operations, and it may be impractical for a compiler to establish every relevant condition—for example, whether a reference is null at a particular point.
public void setAge(int age) {
if (age < 0) {
throw new IllegalArgumentException("age must not be negative");
}
}
This method compiles without declaring throws IllegalArgumentException. It is legal to declare an unchecked exception, and doing so may document an important API condition, but callers still are not required by the compiler to catch it.
By contrast, a checked exception such as IOException must be caught or declared:
public String readFile(Path path) throws IOException {
return Files.readString(path);
}
This distinction is about compiler enforcement and API design—not a guarantee that checked exceptions are recoverable or runtime exceptions are fatal. The term “unchecked” also does not mean the exception is unexpected, safe to ignore, or unworthy of documentation.
How runtime exceptions arise
Code can throw a runtime exception explicitly with throw, a library can throw one when an operation violates its documented conditions, or Java’s execution rules can produce one while evaluating an expression. For example:
Rank #2
int result = 10 / 0; // ArithmeticException
String name = null;
int length = name.length(); // NullPointerException
The Java Language Specification also covers exceptions from failed enabled assertions and certain conditions detected during execution. An exception may therefore originate in your code, a library, or the evaluation of a language operation; it does not necessarily come from the JVM alone.
Common RuntimeException subclasses
| Exception | Common meaning | What to check |
|---|---|---|
NullPointerException |
Code tried to use a null reference. | Trace where the value should have been initialized or validated; repair the invariant rather than adding a blind null check. |
IllegalArgumentException |
A method received an argument outside its accepted conditions. | Validate the value and make the permitted range or format clear to callers. |
IllegalStateException |
An operation is inappropriate for the object’s current state or lifecycle. | Check the order of operations and the object’s state transitions. |
IndexOutOfBoundsException |
An index or range is outside the valid bounds of a collection or sequence. | Check size, index calculations, and loop boundaries. Array and string-specific subclasses include ArrayIndexOutOfBoundsException and StringIndexOutOfBoundsException. |
ClassCastException |
An object was cast to an incompatible type. | Revisit the type model; use a type check when a cast is genuinely conditional. |
ArithmeticException |
An arithmetic operation is invalid, commonly integer division by zero. | Check divisors and assumptions about the values being computed. |
UnsupportedOperationException |
The implementation does not support the requested operation. | Use an implementation that supports it or choose a different operation. |
NoSuchElementException |
Code requested an element that is not available. | Check availability first or use an API that represents absence directly. |
NumberFormatException |
Text cannot be parsed as the requested numeric type. | Validate input or handle invalid user input at the appropriate boundary. |
ConcurrentModificationException |
A collection was structurally changed during iteration in a way the iterator does not support. | Use the iterator’s removal method where appropriate, or choose a suitable concurrent collection. |
These types are not interchangeable diagnoses. For instance, IllegalArgumentException usually points to a caller-provided value that violates a method’s contract; a NullPointerException often points to a missing value or broken invariant. The exception type and message provide clues, but the actual cause depends on the code path.
Read a stack trace and find the cause
A stack trace shows the exception and the call stack captured when it was created. Start with the exception type and message, then find the first frame in your application’s code. In this example, the likely place to inspect is UserService.java:18:
Exception in thread "main" java.lang.NullPointerException:
Cannot invoke "String.length()" because "name" is null
at com.example.UserService.greet(UserService.java:18)
at com.example.Main.main(Main.java:7)
- Read the exception class and message. The message may identify the operation or value involved.
- Find the first stack-trace frame in your own package and open that source line.
- Inspect the inputs and state at that point. Trace backward to learn why the code’s assumption failed.
- Fix the cause, such as invalid input, incorrect ordering, or a missing invariant. Do not simply catch and suppress the exception.
- Add a regression test for the failing condition, and log useful context without exposing secrets or personal data.
Diagnostic methods inherited from Throwable include getMessage(), getCause(), getStackTrace(), getSuppressed(), and printStackTrace(). See the Java SE 17 Throwable reference for stack-trace, cause, and suppressed-exception behavior.
Catch it, propagate it, or declare it?
Catch an exception where the code can make a meaningful decision: recover, choose a valid fallback, translate the failure for a higher-level API, or report a failed operation. Otherwise, let it propagate to a layer that can act on it. Catch the narrowest type the handler can actually handle:
try {
process(input);
} catch (IllegalArgumentException ex) {
showInputError(ex);
}
Avoid catching a broad type just to ignore it:
try {
process(input);
} catch (RuntimeException ignored) {
// Dangerous: the failure is hidden and state may be inconsistent.
}
A broad catch may be appropriate at a deliberate boundary, such as a request handler that converts unexpected failures into a generic response or a job runner that marks one job as failed. That handler should preserve diagnostics, avoid exposing internal details to users, and must not continue as though recovery succeeded when the application is in an unknown state. Repeatedly logging and rethrowing the same exception at every layer can also create duplicate noise; prefer logging where the failure is finally handled or turned into an external result.
If you catch and rethrow while translating between layers, retain the original cause:
Recommended Free Tools
public User loadUser(String id) {
try {
return repository.fetch(id);
} catch (SQLException ex) {
throw new UserRepositoryException("Could not load user " + id, ex);
}
}
The cause chain preserves the lower-level failure for diagnosis while the new type gives callers a more meaningful abstraction. Avoid wrapping an exception without its cause when that original detail matters.
Rank #4
Catch order matters: a subclass catch must appear before a superclass catch. A catch (RuntimeException ex) clause before catch (NullPointerException ex) makes the latter unreachable because it has already been covered.
Do not use exceptions for routine branching when a normal check or return type is clearer. For example, check iterator.hasNext() before calling next() when absence is an expected part of the flow, rather than relying on NoSuchElementException as ordinary control flow.
Designing a custom unchecked exception
Prefer a specific JDK subtype when it accurately describes the failure. Use a custom subclass when the domain meaning matters to callers, tests, or a public API:
public class InvalidOrderException extends RuntimeException {
public InvalidOrderException() {
super();
}
public InvalidOrderException(String message) {
super(message);
}
public InvalidOrderException(String message, Throwable cause) {
super(message, cause);
}
public InvalidOrderException(Throwable cause) {
super(cause);
}
}
Then throw it with a message that explains the violated condition:
Best Value
if (order.items().isEmpty()) {
throw new InvalidOrderException("An order must contain at least one item");
}
A custom runtime exception is useful when callers cannot reasonably recover at every call site, the failure represents invalid input or state, or a distinct type enables meaningful selective handling. A checked exception may be a better API choice when callers are expected to handle a recoverable condition and compiler enforcement adds value. These are design judgments, not language guarantees; unnecessary custom exception types add API surface and maintenance cost.
Document important unchecked conditions even though Java does not force callers to handle them:
/**
* @throws IllegalArgumentException if id is blank
* @throws UserNotFoundException if no user exists for id
*/
public User findUser(String id) {
// ...
}
The standard constructors for RuntimeException include no-argument, message, cause, and message-plus-cause forms. The API also defines a protected constructor for configuring suppression and writable stack traces. In try-with-resources, cleanup failures can be attached as suppressed exceptions to the primary failure; preserve them when writing custom cleanup logic rather than discarding diagnostic information.
RuntimeException is not Error
Error is a separate direct subclass of Throwable, conventionally used for serious conditions—often JVM or linkage failures—from which ordinary applications are not generally expected to recover. A catch (Exception ex) clause catches checked exceptions and RuntimeException subclasses, but not Error subclasses. Application code should not ordinarily catch Error or Throwable; catching Throwable also intercepts errors that the application may not be equipped to handle.
Does an uncaught RuntimeException stop the program?
Not necessarily. A matching catch clause can handle it, and exception propagation searches outward through the call chain for a handler. If none is found, the exception reaches the relevant uncaught-exception boundary; in a typical command-line program, that ends the affected thread and prints a stack trace. An “unhandled” exception means no applicable handler intercepted it along that path, not that nobody could have anticipated it.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

