Best Practices for Handling Exceptions in Java
This article presents comprehensive Java exception‑handling guidelines, covering why exceptions should not be ignored, how to use global handlers, capture specific exceptions, properly close I/O streams, employ try‑with‑resources, avoid returning in finally blocks, log detailed errors, and design custom exceptions for clean, maintainable backend code.
Common Exceptions in Daily Work
Developers often encounter exceptions such as NullPointerException, NumberFormatException, and ClassCastException, and need strategies to handle them elegantly.
1. Do Not Ignore Exceptions
Bad example:
Long id = null;
try {
id = Long.parseLong(keyword);
} catch (NumberFormatException e) {
// ignore exception
}The code silently swallows parsing errors and provides no log, making troubleshooting difficult.
Good example:
Long id = null;
try {
id = Long.parseLong(keyword);
} catch (NumberFormatException e) {
log.info(String.format("keyword:{} 转换成Long类型失败,原因:{}", keyword, e));
}Logging the failure allows quick identification of the problem.
2. Use a Global Exception Handler
Instead of catching exceptions in every service method, define a centralized handler with @RestControllerAdvice and @ExceptionHandler in Spring Boot.
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* Unified exception handling
*/
@ExceptionHandler(Exception.class)
public ApiResult handleException(Exception e) {
if (e instanceof BusinessException) {
BusinessException be = (BusinessException) e;
log.info("业务异常", e);
return ApiResultUtil.error(be.getCode(), be.getMessage());
}
log.error("系统异常", e);
return ApiResultUtil.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "服务器内部错误,请联系系统管理员!");
}
}All controller/service try/catch blocks can be removed, and the handler will wrap and return error responses.
3. Catch Specific Exceptions
Catch concrete exceptions instead of the generic Exception to provide precise handling.
try {
doSomething();
} catch (FileNotFoundException e) {
log.error("文件未找到", e);
} catch (IOException e) {
log.error("IO异常", e);
}4. Close I/O Streams in finally
Closing streams only in the finally block ensures they are released even when an exception occurs.
FileInputStream fis = null;
try {
File file = new File("/tmp/1.txt");
fis = new FileInputStream(file);
byte[] data = new byte[(int) file.length()];
fis.read(data);
for (byte b : data) {
System.out.println(b);
}
} catch (IOException e) {
log.error("读取文件失败,原因:", e);
} finally {
if (fis != null) {
try {
fis.close();
fis = null;
} catch (IOException e) {
log.error("关闭IO流失败,原因:", e);
}
}
}5. Prefer try‑with‑resources
Since JDK 7, resources that implement AutoCloseable can be declared in the try statement, eliminating explicit finally cleanup.
File file = new File("/tmp/1.txt");
try (FileInputStream fis = new FileInputStream(file)) {
byte[] data = new byte[(int) file.length()];
fis.read(data);
for (byte b : data) {
System.out.println(b);
}
} catch (IOException e) {
e.printStackTrace();
log.error("读取文件失败,原因:", e);
}6. Do Not Return from finally
Returning inside finally overrides any value from the try block, leading to incorrect results.
public int divide(int dividend, int divisor) {
try {
return dividend / divisor;
} catch (ArithmeticException e) {
// handle
return -1;
}
}7. Avoid e.printStackTrace()
Printing stack traces to standard error can expose sensitive data and affect performance; use a logger instead.
try {
doSomething();
} catch (IOException e) {
log.error("doSomething处理失败,原因:", e);
}8. Log Detailed Exception Information
Log both the message and the stack trace to capture the full context.
try {
double b = 1/0;
} catch (ArithmeticException e) {
log.error("处理失败,原因:", e);
}9. Do Not Catch and Immediately Rethrow
Catching an exception only to rethrow it after logging causes duplicate logs.
try {
doSomething();
} catch (ArithmeticException e) {
log.error("doSomething处理失败,原因:", e);
throw e;
}10. Prefer Standard Exceptions
Reuse Java’s built‑in exceptions instead of creating custom ones when they convey the same meaning.
if (value < 0) {
throw new IllegalArgumentException("值不能为负");
}11. Document Thrown Exceptions
Javadoc should include @throws tags to describe possible exceptions.
/**
* 处理用户数据
* @param value 用户输入参数
* @return 值
* @throws BusinessException 业务异常
*/
public int doSomething(String value) throws BusinessException {
// 业务逻辑
return 1;
}12. Do Not Use Exceptions for Flow Control
Using try/catch to decide program flow is inefficient; validate inputs before parsing.
Long id = checkValueType(idStr) ? Long.parseLong(idStr) : 1001;13. Custom Exceptions When Necessary
If standard exceptions are insufficient, define a custom exception with additional fields such as an error code.
@AllArgsConstructor
@Data
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = -6735897190745766939L;
private int code;
private String message;
public BusinessException() { super(); }
public BusinessException(String message) {
this.code = HttpStatus.INTERNAL_SERVER_ERROR.value();
this.message = message;
}
}These practices help build high‑quality, maintainable backend services.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
