DEV Community

Cover image for Immutable List in Java
Satyadev Neti
Satyadev Neti

Posted on

Immutable List in Java

Engineering Craftsmanship: Building a Sovereign Immutable List in Java

In an era of "vibe coding" and AI-driven bloat, there is a distinct value in returning to the fundamentals of structural integrity. As I navigate a career pivot toward Site Reliability Engineering (SRE) and Senior Development, I’ve found that the most resilient systems are those built on the principles of data sovereignty and immutability.

Recently, I decided to step away from the standard java.util collections to build something more robust: a truly immutable, persistent linked list using Java 21/25 features.


Why "Sovereign"?

The term "Sovereign" reflects a commitment to local-first software. In a world obsessed with mandatory cloud sync, a sovereign application operates entirely offline, ensuring the user has total ownership of their data. To support this architecture, the underlying data structures must be:

  1. Thread-Safe by Design: Immutability eliminates the need for complex locking mechanisms.
  2. Memory Efficient: Utilizing structural sharing to minimize overhead.
  3. Modern: Leveraging the latest JVM capabilities like Sealed Interfaces and Records.

The Architecture: Sealed Interfaces + Records

By using a sealed interface, we create what functional programmers call a Sum Type. This ensures that our list can only ever be one of two things: Nil (empty) or Cons (a head element and a tail).

The Implementation

package io.sovereign.collections;

import java.util.NoSuchElementException;

public sealed interface ImmutableList<T> permits ImmutableList.Nil, ImmutableList.Cons {

    record Nil<T>() implements ImmutableList<T> {}

    record Cons<T>(T head, ImmutableList<T> tail) implements ImmutableList<T> {}

    default ImmutableList<T> prepend(T value) {
        return new Cons<>(value, this);
    }
}
Enter fullscreen mode Exit fullscreen mode

This structure allows for Structural Sharing. When you prepend an item to the list, you aren't copying the entire array. Instead, you are creating a new Cons node that points to the existing list. This operation is $O(1)$, making it incredibly performant even as the data grows.


Performance and the SRE Mindset

In this implementation, I specifically optimized the functional operations. While map and filter are functional concepts, I implemented them using iterative loops internally. This avoids the dreaded StackOverflowError on large datasets that purely recursive implementations often face on the JVM. It is the balance of functional purity and system-level pragmatism.


Looking Ahead: Project Valhalla

This project isn't just about today; it's about the future of Java. By using Records, this code is already positioned to take advantage of Project Valhalla. Once Value Types land in the JVM, these nodes will have the memory density of primitives, further closing the gap between high-level abstractions and low-level performance.

Conclusion

Building the Sovereign List was an exercise in intentionality. It's a reminder that as software engineers, we aren't just assemblers of libraries; we are craftsmen of systems.

Check out the full source code on GitHub:

GitHub logo devsatya / sovereign-list

A high-performance, persistent, and thread-safe Immutable List for Java, optimized for structural sharing and Project Valhalla.

Sovereign Collections: ImmutableList

A high-performance, persistent, and truly immutable singly-linked list engineered for the modern Java ecosystem (Java 21 to Java 25+).

ImmutableList is built on the principles of Data Sovereignty. It ensures that once data is recorded, it can never be altered by side-effects, race conditions, or external processes. This makes it the ideal foundation for local-first applications, SRE tooling, and privacy-centric software.

🛠 Why ImmutableList?

Traditional Java collections like ArrayList are mutable, leading to defensive copying and complex synchronization in multi-threaded environments. ImmutableList solves this through Persistence and Structural Sharing.

1. Structural Sharing

Instead of deep-copying data, ImmutableList shares existing nodes between different versions of a list. When you prepend an item, a new head is created that points to the original list.

  • Memory Efficiency: Additions are $O(1)$.
  • Zero Data Duplication: Your original data remains untouched and shared in memory.

2. Thread Safety

…

About the Author

I am a Software Developer and SRE based in Hyderabad, currently refining my craft on Ubuntu and exploring the depths of the Java ecosystem.

Top comments (0)