More Functional Thinking

Two Blog Series, One Journey

These companion blog series chart a path from foundational type theory to production-ready optics in Java. Start with the Foundations if you're new to functional programming in Java, or jump straight to the Functional Optics series to see Higher-Kinded-J in action.


Functional Optics for Modern Java NEW — 6 Part Series

Java records and sealed interfaces make immutable data modelling elegant — but updating deeply nested immutable structures still means tedious copy-constructor cascades. This series closes that gap. Across six posts you'll move from the problem, through the theory, and into a fully working production pipeline built with Higher-Kinded-J.

Part 1 — The Immutability Gap: Why Java Records Need Optics

Pattern matching solves the read side beautifully — but what about writes? This opening post reveals how operations that should be one-liners balloon into 25+ lines of manual reconstruction, and introduces optics as the composable answer.

"Pattern matching is half the puzzle; optics complete it."

Part 2 — Optics Fundamentals: Lenses, Prisms, and Traversals

Meet the three core optic types: Lenses for product-type fields, Prisms for sum-type variants, and Traversals for collections. Learn the lens laws, see how @GenerateLenses and @GeneratePrisms eliminate boilerplate, and discover how small, focused optics compose into powerful navigation paths.

Part 3 — Optics in Practice: An Expression Language AST

Theory meets code. Build a complete expression language using sealed interfaces and records, then apply lenses, prisms, and the Focus DSL to implement constant folding and identity simplification — all without hand-written recursion.

Part 4 — The Focus DSL: Traversals and Pattern Rewrites

Scale up from single nodes to entire trees. TraversalPath and bottom-up/top-down strategies handle recursive descent, while modifyWhen and foldMap enable filtered updates and aggregation. A multi-pass optimisation pipeline brings constant folding, dead-branch elimination, and common-subexpression detection together.

Part 5 — The Effect Path API: Railway-Style Error Handling

Introduce effects into optics. MaybePath, EitherPath, ValidationPath, and VTaskPath let the same traversal code work across different computational contexts — fail-fast for quick feedback, accumulating for comprehensive validation, and concurrent via virtual threads.

Part 6 — From Theory to Practice

The capstone. Wire Focus DSL + Effect Paths into a four-phase expression pipeline, integrate with Spring Boot via hkj-spring-boot-starter, generate optics for third-party types with @ImportOptics, and map out a pragmatic incremental migration path for real teams.

Companion Code

All six parts have runnable examples in the expression-language-example repository. Clone it and follow along.


Foundations: Types and Functional Patterns

This earlier series explores the foundational ideas that inspired Higher-Kinded-J's development. Each post builds the theoretical knowledge that underpins the optics series above.


Previous: Const Next: Glossary