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 modern Scala, ZIO, and zio-prelude

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

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

Pre-1.0 and changing fast

Nothing is released yet. Snapshots of main are published to Maven Central's snapshot repository, and the API changes between them. Pin a snapshot you have tested.

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 part of its API, not an afterthought. Its design comes from modern Scala's collections and from ZIO.

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, not by guessing.

    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 a switch over 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.

A short tour

// Validation keeps every error, not the first one
Validation<String, User> user = Validation.zipWith(name(""), age(-1), email("jules"), User::new);
String 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>
Option<Integer> sum = Option.zipWith(Option.some(1), Option.some(2), Option.some(3), (a, b, c) -> a + b + c);

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

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

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

Where the ideas come from

  • Modern Scala


    The Scala 3 collections: the Vector builder, fast set operations on sorted sets, grouped and sliding that return collections, 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. Snapshots of main are on Maven Central's snapshot repository.

<repositories>
    <repository>
        <id>central-portal-snapshots</id>
        <url>https://central.sonatype.com/repository/maven-snapshots/</url>
        <snapshots><enabled>true</enabled></snapshots>
        <releases><enabled>false</enabled></releases>
    </repository>
</repositories>

<dependency>
    <groupId>com.guizmaii</groupId>
    <artifactId>zazr-core</artifactId>
    <version>0.1.0-SNAPSHOT</version>
</dependency>
repositories {
    maven("https://central.sonatype.com/repository/maven-snapshots/")
}

dependencies {
    implementation("com.guizmaii:zazr-core:0.1.0-SNAPSHOT")
}

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

Get started