// Created on savesnippets.com · https://savesnippets.com/WR9qlYp0tqgKa0 // Base — extend RuntimeException for unchecked (most modern Java code) public class AppException extends RuntimeException { public AppException(String message) { super(message); } public AppException(String message, Throwable cause) { super(message, cause); } } public class NotFoundException extends AppException { private final String resource; private final String id; public NotFoundException(String resource, String id) { super(resource + " not found: " + id); this.resource = resource; this.id = id; } public String resource() { return resource; } public String id() { return id; } } public class ValidationException extends AppException { private final String field; public ValidationException(String field, String message) { super("invalid " + field + ": " + message); this.field = field; } public String field() { return field; } } // Caller can match by type class Service { void handle() { try { // ... do work ... } catch (NotFoundException nfe) { System.out.printf("404 %s/%s%n", nfe.resource(), nfe.id()); } catch (ValidationException ve) { System.out.printf("400 field=%s%n", ve.field()); } catch (AppException ae) { System.err.println("500 " + ae.getMessage()); } } }