outcome is a Java framework that provides a formal boundary between deterministic application code and fallible, non-deterministic operations such as network calls, database queries, and external API requests.
The problem
Java’s exception model conflates three fundamentally different failure categories: operational failures (network timeouts, service unavailability), defects (null pointers, logic errors), and terminal errors (out of memory). This leads to inconsistent error handling, ad-hoc retry loops, and swallowed exceptions across codebases.
How it works
Outcome replaces try/catch with a sealed Outcome<T> type — either Ok (success with a value) or Fail (a structured failure). This enables exhaustive handling via Java’s pattern matching:
return switch (outcome) {
case Outcome.Ok(var user, var _) -> "Hello, " + user.name();
case Outcome.Fail(var failure, var _) -> "Error: " + failure.message();
};
Key capabilities
- Explicit boundaries — the
Boundaryclass marks the crossing point between deterministic code and fallible operations, catching checked exceptions and classifying them into structured failures - Structured failure data — each
Failurecarries a namespaced ID, type (TRANSIENT, PERMANENT, or DEFECT), message, retry guidance, correlation ID, and observability tags - Automatic failure classification — common exceptions are mapped to appropriate failure types (e.g.
SocketTimeoutException→ transient network timeout, HTTP 429 → transient with rate-limit handling) - Policy-driven retries — centralised retry logic with fixed, exponential backoff, and immediate policies, respecting the failure’s
retryAfterhint and configurable time budgets - Guided retry — for feedback-loop scenarios such as LLM interactions, where failure context from one attempt informs the next
- Functional composition — chain operations with
map,flatMap,recover, andrecoverWith, preserving correlation IDs through the pipeline - Built-in observability — the
OpReporterinterface receives failure events for logging, metrics, and alerting, with built-in reporters for SLF4J and JSON-lines output - Defect escalation — bugs (unchecked exceptions) propagate and page operators via
OperationalExceptionHandler, rather than being silently swallowed
Design principle
Recoverable failures flow as values. Defects crash and page. Terminal errors terminate. Outcome makes this distinction explicit and enforceable.
Repository
View the source and documentation on GitHub.
