Custom Exception Hierarchy
Design a clean exception hierarchy with custom exceptions, error codes, and exception mapping.
// Base application exception
public abstract class AppException extends RuntimeException {
private final String errorCode;
private final int httpStatus;
protected AppException(String errorCode, int httpStatus, String message) {
super(message);
this.errorCode = errorCode;
this.httpStatus = httpStatus;
}
protected AppException(String errorCode, int httpStatus, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
this.httpStatus = httpStatus;
}
public String getErrorCode() { return errorCode; }
public int getHttpStatus() { return httpStatus; }
}
// Specific exceptions
public class NotFoundException extends AppException {
public NotFoundException(String resource, Object id) {
super("NOT_FOUND", 404,
String.format("%s not found with id: %s", resource, id));
}
}
public class ValidationException extends AppException {
private final Map<String, String> fieldErrors;
public ValidationException(Map<String, String> fieldErrors) {
super("VALIDATION_ERROR", 400, "Validation failed");
this.fieldErrors = fieldErrors;
}
public Map<String, String> getFieldErrors() { return fieldErrors; }
}
public class ConflictException extends AppException {
public ConflictException(String message) {
super("CONFLICT", 409, message);
}
}
public class RateLimitException extends AppException {
public RateLimitException() {
super("RATE_LIMITED", 429, "Too many requests");
}
}
// Usage in service
class UserService {
public User findById(Long id) {
return repo.findById(id)
.orElseThrow(() -> new NotFoundException("User", id));
}
public User create(CreateUserDTO dto) {
if (repo.existsByEmail(dto.email())) {
throw new ConflictException("Email already registered");
}
return repo.save(toEntity(dto));
}
}Use Cases
- Consistent error handling across services
- Mapping business errors to HTTP status codes
- Structured exception hierarchies for large codebases
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
Java Optional — Avoid NullPointerException
Use Optional to handle nullable values safely with map, flatMap, orElse, and ifPresent patterns.
Best for: Eliminating NullPointerException in business logic
Spring Boot Global Exception Handler
Centralized error handling with @ControllerAdvice for validation errors, 404s, and custom exceptions.
Best for: Consistent error responses across all endpoints
Try-With-Resources and AutoCloseable
Manage resources safely with try-with-resources: files, connections, streams, and custom resources.
Best for: Safe resource management preventing leaks
Java Enums — Methods, Fields, and Interfaces
Advanced enum patterns: enums with fields, abstract methods, implementing interfaces, and enum maps.
Best for: Type-safe constants with behavior