Best Practices for Handling Exceptions in Java
This article explains essential Java exception‑handling techniques, including cleaning resources in finally blocks or using try‑with‑resources, declaring specific exceptions, documenting throws clauses, providing descriptive messages, catching the most specific exceptions first, avoiding catching Throwable, not ignoring exceptions, and correctly wrapping exceptions without losing original causes.
Cleaning Resources in Finally Block
When using resources such as InputStream , closing them inside the try block can cause leaks if an exception is thrown; the recommended practice is to move cleanup code to a finally block or use the try‑with‑resources statement.
public void doNotCloseResourceInTry() {
FileInputStream inputStream = null;
try {
File file = new File("./tmp.txt");
inputStream = new FileInputStream(file);
// use the inputStream to read a file
// do NOT do this
inputStream.close();
} catch (FileNotFoundException e) {
log.error(e);
} catch (IOException e) {
log.error(e);
}
}The above code works when no exception occurs, but if an exception is thrown the explicit close() call is skipped, leaving the resource open.
Properly placing cleanup in finally or using try‑with‑resource ensures the resource is always released.
public void closeResourceInFinally() {
FileInputStream inputStream = null;
try {
File file = new File("./tmp.txt");
inputStream = new FileInputStream(file);
// use the inputStream to read a file
} catch (FileNotFoundException e) {
log.error(e);
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
log.error(e);
}
}
}
}
public void automaticallyCloseResource() {
File file = new File("./tmp.txt");
try (FileInputStream inputStream = new FileInputStream(file)) {
// use the inputStream to read a file
} catch (FileNotFoundException e) {
log.error(e);
} catch (IOException e) {
log.error(e);
}
}Specify the Most Specific Exception
Declare the most specific exception type in a method signature to make the code easier to understand.
public void doNotDoThis() throws Exception {
...
}
public void doThis() throws NumberFormatException {
...
}Using NumberFormatException makes it clear that the method fails due to a number‑formatting error.
Document Exceptions in Javadoc
When a method declares a thrown exception, add a @throws tag in the Javadoc to describe the circumstances.
/**
* This method does something extremely useful ...
*
* @param input
* @throws MyBusinessException if ... happens
*/
public void doSomething(String input) throws MyBusinessException {
...
}Include Descriptive Information When Throwing
Provide a concise description with the exception to aid logging and monitoring.
try {
new Long("xyz");
} catch (NumberFormatException e) {
log.error(e);
}Catch the Most Specific Exception First
When multiple catch blocks exist, place the most specific ones before the more general ones; otherwise the general block will prevent the specific one from executing.
public void catchMostSpecificExceptionFirst() {
try {
doSomething("A message");
} catch (NumberFormatException e) {
log.error(e);
} catch (IllegalArgumentException e) {
log.error(e);
}
}Never Catch Throwable
Throwable includes both exceptions and errors; catching it can mask unrecoverable JVM errors. Only catch exceptions you can handle.
public void doNotCatchThrowable() {
try {
// do something
} catch (Throwable t) {
// don't do this!
}
}Do Not Swallow Exceptions
A catch block that does nothing hides problems; at a minimum, log the exception.
public void doNotIgnoreExceptions() {
try {
// do something
} catch (NumberFormatException e) {
// this will never happen
}
}
public void logAnException() {
try {
// do something
} catch (NumberFormatException e) {
log.error("This should never happen: " + e);
}
}Avoid Logging and Rethrowing the Same Exception
Logging an exception and then rethrowing it leads to duplicate log entries; instead, either log at a higher level or wrap the exception with additional context.
try {
new Long("xyz");
} catch (NumberFormatException e) {
log.error(e);
throw e; // duplicate log
}Wrap Exceptions Without Losing the Original Cause
When converting a standard exception to a custom one, pass the original exception as the cause so that stack traces remain complete.
public void wrapException(String input) throws MyBusinessException {
try {
// do something
} catch (NumberFormatException e) {
throw new MyBusinessException("A message that describes the error.", e);
}
}Summary
When throwing or catching exceptions, consider resource cleanup, specificity, documentation, descriptive messages, ordering of catch blocks, avoiding Throwable , not ignoring or double‑logging exceptions, and preserving the original cause when wrapping. These practices improve code readability, API usability, and collaborative understanding of error handling.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.