Skip to content
Zaz, the Zazr capybara, with a yuzu on its head

Java 25+ · no runtime dependencies · Apache 2.0

Zazr

Modern Functional Programming for Java 25+ Inspired by Scala 2.13+, ZIO, and zio-prelude

// one call per arity, never a Tuple2<Tuple2<A, B>, C>
var sum = Option.zipWith(Option.some(1), Option.some(2), Option.some(3),
    (a, b, c) -> a + b + c); // Option<Integer>

// total on a collection that cannot be empty
var best = NonEmptyVector.of(7, 3, 9).max(Integer::compare); // Integer
// sum is Some(6), best is 9

What Zazr is

Zazr gives Java immutable collections and the types that make functional code pleasant: Option, Either, Try, Validation and Lazy. It is built for Java 25: sealed interfaces, records and pattern matching are at the core of its API. Its collections come from the Scala 2.13 collections library, which Scala 3 uses unchanged; its names and most of its control types come from ZIO and zio-prelude, and Using from Scala's scala.util.Using.

What it brings

  • Collections that state their cost


    Every operation whose cost depends on the size documents it, and one page lists them all. You choose a collection for what you do with it.

    Complexity

  • Persistent collections you can build fast


    A builder fills a collection in place and hands it over once, so building one in a loop copies nothing.

    Builders

  • Errors you do not lose


    Validation collects every error instead of stopping at the first, in a list that is never empty.

    Validation

  • Combine up to eight values in one call


    zipWith takes all of them and a function of their values, with no nested tuples to unpack.

    zip at arity N

  • Collections that cannot be empty


    On a NonEmptyVector, head, max and reduce cannot fail, and the return types tell you when that guarantee is lost.

    NonEmptyVector

  • Pattern matching on results


    Option, Either, Try and Validation are sealed interfaces of records, so pattern matching on them is checked by the compiler.

    Control types

  • No null inside


    Values and collections reject it, and absence is an Option.

  • Java interop without copies


    asJava() gives a read-only java.util view in constant time, and the way back does not copy either.

    Java interop

  • Names that say what happens


    zip, collectAll, catchAll, mapBoth: the vocabulary of ZIO, with no theory to learn first.

Zazr is AI ready

Teach your coding assistant Zazr. The Zazr Agent Skill gives it the rules, the names and the sharp edges, so it writes idiomatic Zazr code.

Add it to your assistant The skill on GitHub

A short tour

// Validation keeps every error, not the first one
var user = Validation.zipWith(name(""), age(-1), email("jules"), User::new); // Validation<String, User>
var message = switch (user) {
    case Valid(var u) -> "hello " + u.name();
    case Invalid(var errors) -> errors.mkString(", ");
};
// "name is blank, age is negative, email has no @"

// zip at any arity up to 8, no Tuple2<Tuple2<A, B>, C>
var sum = Option.zipWith(Option.some(1), Option.some(2), Option.some(3),
    (a, b, c) -> a + b + c); // Option<Integer>

// total operations on a collection that cannot be empty
var scores = NonEmptyVector.of(7, 3, 9);
var best   = scores.max(Integer::compare); // Integer

// a builder instead of repeated append
var builder = Vector.<Integer>newBuilder();
for (int i = 0; i < 1_000; i++) {
    builder.add(i);
}
var numbers = builder.result();

name, age and email each return a Validation<String, ...>; Validation shows them.

Where the ideas come from

  • Scala 2.13+ collections


    The Scala 2.13 collections library, which Scala 3 uses unchanged: the Vector and its builder, the hash tries of HashSet and HashMap, the fully lazy LazyList, and a table of what each operation costs. Sealed interfaces, records and switch bring Scala's pattern matching to Java.

  • ZIO


    The operation names (zipWith, collectAll, forEach, tap, catchAll, mapBoth), one name per operation, and one default sequence with documented costs, as Chunk is in ZIO.

  • zio-prelude


    Validation with its errors in a non-empty collection, zip to combine independent values, and a non-empty collection whose return types say when it may become empty.

Zazr started as a fork of Vavr. Coming from Vavr? This page lists what changed.

Install

JDK 25 or later, no runtime dependencies. Zazr is on Maven Central.

<dependency>
    <groupId>dev.zazr</groupId>
    <artifactId>zazr-core</artifactId>
    <version>0.1.0</version>
</dependency>
dependencies {
    implementation("dev.zazr:zazr-core:0.1.0")
}

dev.zazr:zazr-test adds property-based testing; see Testing with zazr-test.

Get started