Compared to Vavr¶
In one line: Vavr is Scala 2.12, Zazr is Scala 2.13.
Zazr is a fork of the latest Vavr, reshaped for Java 25. Its collections follow the
Scala 2.13 collections library, which Scala 3 uses unchanged; its names and most of its control types follow ZIO
and zio-prelude, and Using follows Scala's scala.util.Using. It is not a drop-in replacement: the package is
dev.zazr, and the changes below are deliberate. Design explains the ideas behind them, and the
release notes list what each release changes.
Removed¶
| Removed | Use instead |
|---|---|
Match, Case, $, API.For |
switch with record patterns and when guards; zip/zipWith for comprehensions |
Future, Promise, Task |
CompletableFuture, virtual threads; Try.fromCompletableFuture and toCompletableFuture bridge |
Array, CharSeq |
Vector; String and Vector<Character> |
Tree, BitSet, PriorityQueue, the Multimap family |
Map<K, Vector<V>> with groupBy |
Seq, IndexedSeq, LinearSeq, Foldable, Value |
the concrete type, or Traversable for what every collection does at the same cost |
Function0, Function1, Function2, CheckedFunction0 |
Supplier, Function, BiFunction, Callable |
PartialFunction, collect(PartialFunction) |
collect(Function<A, Option<B>>) with pattern matching inside the lambda |
Serializable on every type |
none; no Zazr type is Serializable |
Either projections, Validation.Builder, combine, ap |
mapLeft, flip, fold; zip and zipWith at arity N |
Try.withResources |
Using |
the public Iterator type, reverseIterator(), iterator(int) |
iterator(), a java.util.Iterator; reverse().iterator(), drop(n).iterator() |
toJavaList, toJavaSet, toJavaMap..., asJavaMutable |
the view asJava() or asJavaMap(); copy with new ArrayList<>(vector.asJava()) |
unfoldLeft, unfoldRight |
unfold (see below) |
Renamed¶
| Vavr | Zazr |
|---|---|
ap, combine(...).ap(f) |
zip, zipWith, static zip(a, b, c), zipWith(a, b, c, f) |
sequence |
collectAll |
traverse |
static forEach |
bimap |
mapBoth |
peek, peekLeft, onFailure, onSuccess, onEmpty |
tap, tapLeft, tapError, tap, tapNone |
mapTo(value) |
as(value) on a sequence or a set; map(x -> value) on a control type or a map |
swap on Either |
flip |
Stream, toStream() |
LazyList, toLazyList() |
length() |
size() |
Tuple.sequence1 to sequence8, toSeq() |
Tuple.unzip1 to unzip8, toVector() |
recover, recoverWith |
catchAll, catchSome, catchAllWith, catchSomeWith |
mapFailure(Case...) |
mapError(Function) |
andFinally |
ensuring |
Option.of(nullable) |
Option.ofNullable |
Validation.cond, Either.cond |
fromPredicate |
getOrElseGet(Function) |
a getOrElse(Function) overload |
toJavaArray |
toArray |
removeAll(Predicate) on a sequence |
reject(Predicate); removeAll takes the elements to remove |
removeAll(BiPredicate), removeKeys, removeValues on a map |
reject(BiPredicate), rejectKeys, rejectValues; removeAll takes the keys to remove |
sum(), product(), average() |
sumInt, sumLong, sumDouble, productInt, productLong, productDouble, average, each taking the function that reads the number from an element |
Behaviour that differs¶
- No
nullinside.Some,Right,Success,Validand every collection reject it;Option.some(null)throws instead of buildingSome(null). - Control types are not
Iterable.for (x : option)no longer compiles; each type has explicit conversions (toVector(),toOption()...). Validationkeeps every error. Its error side is aNonEmptyVector<E>, andzipaccumulates without changing the type.- Sets and maps have no positional methods (
head,take,sliding...), except the ordered ones:LinkedHashSet,LinkedHashMap,TreeSet,TreeMap. grouped,slidingandcrossProductreturn a collection, not anIterator: of the receiver's type on the sequences (Vector<Vector<T>>...), aVectorof the receiver's type forgroupedandslidingon the ordered sets and maps and onNonEmptyVector(Vector<TreeSet<T>>), and aVectorforcrossProduct(power)onNonEmptyVector.tapon a collection runs on every element. Vavr'speekran on the first one.- Two
Try.Failures are equal when they hold the sameThrowableinstance, not when their stack traces match. unfoldreturns the element first, then the next state, as in Scala and ZIO, and gives the elements in the order it produces them: it is Vavr'sunfoldRight. Vavr'sunfoldandunfoldLeftreturned(nextState, element)and gave the elements in reverse order. When the element and the state have the same type, Vavr code still compiles with the roles swapped:List.unfold(10, x -> x == 0 ? Option.none() : Option.some(Tuple.of(x - 1, x)))keeps the state at 10 and never returns. Swap the tuple (Tuple.of(x, x - 1)) when moving it over, andreverse()the result where the order matters.LazyList, Vavr'sStream, is fully lazy. Nothing is computed before it is read, not even its first element or whether it is empty (LazyList).- Every positional method documents its cost (complexity).