Browse Clojure Foundations for Java Developers

Practical Examples of Immutability

Update nested data with assoc/update without mutation, and model state transitions as values.

Immutability becomes real when you stop thinking “how do I change this object?” and start thinking “what new value should this function produce?”

Here is the basic shape you will use constantly:

1(def order {:id 1 :status :new :items [{:sku "A" :qty 1}]})
2
3(update order :status (constantly :paid))

What to focus on

  • Prefer update, assoc, dissoc for shallow changes.
  • Use update-in / assoc-in for nested structures.
  • Keep transformations pure so they are easy to test and reuse.

Java mental model: instead of “mutate a DTO”, treat state changes like producing a new immutable DTO (but without boilerplate constructors and setters).

In this section

  • Transforming Collections
    Move from mutable loops to value-oriented collection pipelines with `map`, `filter`, `reduce`, and threading macros.
  • Immutability in Application State
    Model state changes as pure transitions between immutable values, and keep atoms or other references at the boundary.
  • Refactoring Imperative Code
    Use a repeatable recipe to move from mutable Java-style workflows to pure Clojure functions over immutable data.
Revised on Friday, April 24, 2026