Fundamentals 11 min read

When Should You Use Exceptions in Java? Best Practices Explained

This article explains the proper use of Java exceptions, distinguishing between checked and unchecked exceptions, showing when to throw them, how to design APIs that avoid misuse, and offering guidelines for documenting and handling exceptions effectively.

ITFLY8 Architecture Home
ITFLY8 Architecture Home
ITFLY8 Architecture Home
When Should You Use Exceptions in Java? Best Practices Explained

When to Use Exceptions

The ideal time to discover errors is at compile time, before the program runs. Since compilation cannot catch all problems, remaining issues must be handled at runtime, requiring the error source to convey appropriate information to a receiver that knows how to handle it.

Only Use Exceptions for Exceptional Situations

Using exceptions for normal control flow is a misuse. The following code demonstrates a typical abuse where an infinite loop is terminated by catching an ArrayIndexOutOfBoundsException:

try {
    int i = 0;
    while (true) {
        range[i++].climb();
    }
} catch (ArrayIndexOutOfBoundsException e) {
    // ignore
}

A proper approach replaces the loop with a standard iteration:

for (Mountain m : range) {
    m.climb();
}

Exceptions should never be used for regular control flow; they are intended for abnormal conditions, and placing code inside try‑catch blocks can prevent JVM optimizations.

Code reuse is a rule; exceptions are no exception.

Java Exception Architecture

All exception classes inherit from Throwable. Errors (subclass of Throwable) represent unrecoverable conditions and should not be caught by application code. Most programmers work with Exception subclasses, which are divided into unchecked and checked exceptions.

Unchecked Exceptions

These are subclasses of RuntimeException and indicate programming errors, typically precondition violations such as passing null where it is not allowed. Unchecked exceptions should be used when the API contract is broken by the caller.

Checked Exceptions

These are direct subclasses of Exception (excluding RuntimeException) and are intended for conditions that the caller can reasonably recover from. An API should force the caller to handle such situations via throws declarations.

When a checked exception represents a situation where the caller can take immediate useful action, it is appropriate to use it. For example, a payment API might throw a checked exception when the account balance is insufficient.

Avoid Overusing Checked Exceptions

While checked exceptions improve reliability by forcing handling, excessive use makes APIs cumbersome. Use them only when the caller can meaningfully respond.

catch (CheckedException e) {
    throw new AssertionError();
}

Another example:

catch (CheckedException e) {
    e.printStackTrace();
    System.exit(1);
}

If the caller cannot do better than terminating the program, an unchecked exception is preferable.

Prefer Standard Exceptions

Java provides a set of common unchecked exceptions that cover most API needs.

Throw Exceptions That Match the Abstraction

Higher‑level code should catch low‑level exceptions and re‑throw exceptions that make sense at the higher abstraction level.

try {
    // low‑level operation
} catch (LowerLevelException e) {
    throw new HigherLevelException(...);
}
Iterator i = ...;
try {
    return i.next();
} catch (NoSuchElementException e) {
    throw new IndexOutOfBoundsException("Index: " + index);
}

Exception chaining can preserve the original cause for debugging:

try {
    // low‑level operation
} catch (LowerLevelException cause) {
    throw new HigherLevelException(cause);
}

Maintain Failure Atomicity

After an exception, objects should remain in a well‑defined state. Methods should aim for failure atomicity, either by using immutable objects, ordering operations before state changes, providing recovery code, or operating on temporary copies.

Document Exceptions Properly

Always declare checked exceptions explicitly and use Javadoc @throws tags to describe the conditions under which each exception is thrown. Never declare throws Exception or throws Throwable as they hide specific failures.

Documenting unchecked exceptions in the API contract helps callers understand preconditions and avoid misuse.

Do Not Ignore Exceptions

An empty catch block defeats its purpose; at minimum, it should contain a comment explaining why the exception is ignored.

Appendix A

Direct subclasses of java.lang.RuntimeException include:

AnnotationTypeMismatchException

ArithmeticException

ArrayStoreException

BufferOverflowException

BufferUnderflowException

CannotRedoException

CannotUndoException

ClassCastException

CMMException

ConcurrentModificationException

DataBindingException

DOMException

EmptyStackException

EnumConstantNotPresentException

EventException

IllegalArgumentException

IllegalMonitorStateException

IllegalPathStateException

IllegalStateException

ImagingOpException

IncompleteAnnotationException

IndexOutOfBoundsException

JMRuntimeException

LSException

MalformedParameterizedTypeException

MirroredTypeException

MirroredTypesException

MissingResourceException

NegativeArraySizeException

NoSuchElementException

NoSuchMechanismException

NullPointerException

ProfileDataException

ProviderException

RasterFormatException

RejectedExecutionException

SecurityException

SystemException

TypeConstraintException

TypeNotPresentException

UndeclaredThrowableException

UnknownAnnotationValueException

UnknownElementException

UnknownTypeException

UnmodifiableSetException

UnsupportedOperationException

WebServiceException

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Exception Handlingbest practicesapi-designChecked ExceptionsUnchecked Exceptions
ITFLY8 Architecture Home
Written by

ITFLY8 Architecture Home

ITFLY8 Architecture Home - focused on architecture knowledge sharing and exchange, covering project management and product design. Includes large-scale distributed website architecture (high performance, high availability, caching, message queues...), design patterns, architecture patterns, big data, project management (SCRUM, PMP, Prince2), product design, and more.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.