Skip to content

Getting started

New to functional programming? Start with why Zazr is useful.

Requirements

JDK 25 or later. Zazr has no runtime dependency.

Add the dependency

Zazr is on Maven Central. The current version is 0.5.0; the releases list what each version changes.

<dependency>
    <groupId>dev.zazr</groupId>
    <artifactId>zazr-core</artifactId>
    <version>0.5.0</version>
</dependency>

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

zazr-test is optional: it adds property-based testing.

If your project uses Java modules (a module-info.java), add requires dev.zazr; to it. Projects without a module-info.java need nothing more.

Where things are

Package Types
dev.zazr.control Option, Either, Try, Validation, Using
dev.zazr.collection Vector, NonEmptyVector, List, Queue, LazyList, HashSet, LinkedHashSet, TreeSet, NonEmptySet, NonEmptySortedSet, HashMap, LinkedHashMap, TreeMap, NonEmptyMap, NonEmptySortedMap
dev.zazr Lazy, Tuple and Tuple0 to Tuple8, Function3 to Function8, the Checked* functional interfaces

List shares its name with java.util.List: import the Zazr one and spell the JDK one out, as the examples on this site do.

Five minutes of Zazr

A value that may be absent is an Option. It never holds null; use ofNullable to wrap a value that may be null.

var name     = Option.ofNullable(System.getenv("ZAZR_DOCS_UNSET")); // Option<String>
var greeting = name.map(n -> "hello " + n).getOrElse("hello stranger");
// "hello stranger"

Option, Either, Try and Validation are sealed interfaces of records, so pattern matching on them with a switch is exhaustive, and record patterns take the records apart.

var parsed = Either.<String, Integer>right(42);
var text = switch (parsed) {
    case Right(var n) -> "got " + n;
    case Left(var error) -> "failed: " + error;
};

A computation that may throw is a Try; catchAll recovers.

var port  = Try.of(() -> Integer.parseInt("80a")); // Try<Integer>
var value = port.catchAll(error -> 8080).get();
// 8080

Vector is the default sequence. Every operation returns a new Vector, and access by index takes a few steps at any size.

var numbers = Vector.of(1, 2, 3, 4);
var doubled = numbers.map(n -> n * 2).append(10); // Vector<Integer>
var third   = doubled.get(2);
// doubled is Vector(2, 4, 6, 8, 10), third is 6

Next

  • Control types: Option, Either, Try, Validation and Lazy, and which one to pick.
  • Validation: checks that report every error at once.
  • Collections: which collection to choose, and what each operation costs.