Object-functional language extension to Java 8+ providing persistent collections, functional abstractions, and monadic control types.
—
Comprehensive immutable collection library with persistent data structures including sequential collections, sets, maps, and specialized collections optimized for functional programming.
Core interfaces that define the collection hierarchy and common operations.
/**
* Root interface for all traversable collections
*/
interface Traversable<T> extends Value<T> {
// Factory methods
static <T> Traversable<T> empty();
static <T> Traversable<T> of(T... elements);
// Basic operations
int size();
boolean isEmpty();
boolean contains(T element);
// Transformation operations
<U> Traversable<U> map(Function<? super T, ? extends U> mapper);
Traversable<T> filter(Predicate<? super T> predicate);
<U> U foldLeft(U zero, BiFunction<? super U, ? super T, ? extends U> combine);
<U> U foldRight(U zero, BiFunction<? super T, ? super U, ? extends U> combine);
// Terminal operations
String mkString();
String mkString(String delimiter);
String mkString(String prefix, String delimiter, String suffix);
}
/**
* Base interface for sequential collections
*/
interface Seq<T> extends Traversable<T> {
// Access operations
T get(int index);
int indexOf(T element);
int lastIndexOf(T element);
// Transformation operations
Seq<T> append(T element);
Seq<T> prepend(T element);
Seq<T> insert(int index, T element);
Seq<T> remove(T element);
Seq<T> removeAt(int index);
// Subsequence operations
Seq<T> slice(int beginIndex, int endIndex);
Seq<T> take(int n);
Seq<T> drop(int n);
Seq<T> reverse();
// Grouping operations
<K> Map<K, ? extends Seq<T>> groupBy(Function<? super T, ? extends K> classifier);
}
/**
* Interface for indexed sequential collections with O(1) random access
*/
interface IndexedSeq<T> extends Seq<T> {
// Override for performance
T get(int index); // O(1) access
}
/**
* Interface for linear sequential collections with O(1) head/tail access
*/
interface LinearSeq<T> extends Seq<T> {
T head();
LinearSeq<T> tail();
boolean isEmpty();
}Immutable singly-linked list implementation optimized for prepend operations and sequential access.
/**
* Immutable singly-linked list (LIFO stack)
*/
interface List<T> extends LinearSeq<T> {
// Factory methods
static <T> List<T> empty();
static <T> List<T> of();
static <T> List<T> of(T element);
static <T> List<T> of(T... elements);
static <T> List<T> ofAll(Iterable<? extends T> elements);
static <T> List<T> fill(int n, T element);
static <T> List<T> fill(int n, Supplier<? extends T> supplier);
static List<Integer> range(int from, int toExclusive);
static List<Integer> rangeClosed(int from, int toInclusive);
// Stack operations (O(1))
T head(); // Get first element
List<T> tail(); // Get all but first element
List<T> prepend(T element); // Add to front
static <T> List<T> cons(T head, List<T> tail); // Construct from head and tail
// List operations
List<T> append(T element); // Add to end (O(n))
List<T> appendAll(Iterable<? extends T> elements);
List<T> prependAll(Iterable<? extends T> elements);
// Transformation operations (return new List)
<U> List<U> map(Function<? super T, ? extends U> mapper);
List<T> filter(Predicate<? super T> predicate);
<U> List<U> flatMap(Function<? super T, ? extends Iterable<? extends U>> mapper);
List<T> distinct();
List<T> sorted();
List<T> sorted(Comparator<? super T> comparator);
// Combining operations
List<T> removeFirst(Predicate<? super T> predicate);
List<T> removeLast(Predicate<? super T> predicate);
List<T> removeAll(T element);
List<T> replace(T currentElement, T newElement);
List<T> replaceAll(T currentElement, T newElement);
// Zipping operations
<U> List<Tuple2<T, U>> zip(Iterable<? extends U> that);
<U, R> List<R> zipWith(Iterable<? extends U> that, BiFunction<? super T, ? super U, ? extends R> mapper);
List<Tuple2<T, Integer>> zipWithIndex();
}Usage Examples:
import io.vavr.collection.List;
// Creating lists
List<Integer> empty = List.empty();
List<Integer> numbers = List.of(1, 2, 3, 4, 5);
List<String> names = List.of("Alice", "Bob", "Charlie");
// Stack operations (efficient)
List<Integer> withZero = numbers.prepend(0); // [0, 1, 2, 3, 4, 5]
Integer first = numbers.head(); // 1
List<Integer> rest = numbers.tail(); // [2, 3, 4, 5]
// Functional operations
List<Integer> doubled = numbers.map(x -> x * 2);
List<Integer> evens = numbers.filter(x -> x % 2 == 0);
List<String> words = List.of("hello", "world").map(String::toUpperCase);
// Combining lists
List<Integer> extended = numbers.append(6).appendAll(List.of(7, 8, 9));
List<Integer> combined = List.of(0).appendAll(numbers);
// Pattern matching on lists
String describe(List<Integer> list) {
return list.isEmpty() ? "empty" :
list.tail().isEmpty() ? "single: " + list.head() :
"multiple starting with " + list.head();
}High-performance immutable indexed sequence with efficient random access and updates.
/**
* Immutable indexed sequence with O(log n) access and updates
*/
class Vector<T> implements IndexedSeq<T> {
// Factory methods
static <T> Vector<T> empty();
static <T> Vector<T> of(T... elements);
static <T> Vector<T> ofAll(Iterable<? extends T> elements);
static <T> Vector<T> fill(int n, T element);
static Vector<Integer> range(int from, int toExclusive);
// Indexed access (O(log n))
T get(int index);
Vector<T> update(int index, T element);
// Modification operations (O(log n))
Vector<T> append(T element);
Vector<T> prepend(T element);
Vector<T> insert(int index, T element);
Vector<T> removeAt(int index);
// Transformation operations
<U> Vector<U> map(Function<? super T, ? extends U> mapper);
Vector<T> filter(Predicate<? super T> predicate);
Vector<T> sorted();
Vector<T> sorted(Comparator<? super T> comparator);
// Subsequence operations
Vector<T> slice(int beginIndex, int endIndex);
Vector<T> take(int n);
Vector<T> drop(int n);
Vector<T> reverse();
}Immutable wrapper around Java arrays providing indexed access with functional programming operations.
/**
* Immutable wrapper for Object[] with O(1) indexed access
*/
class Array<T> implements IndexedSeq<T> {
// Factory methods
static <T> Array<T> empty();
static <T> Array<T> of(T... elements);
static <T> Array<T> ofAll(Iterable<? extends T> elements);
static <T> Array<T> ofAll(java.util.stream.Stream<? extends T> javaStream);
static <T> Array<T> fill(int n, T element);
static <T> Array<T> fill(int n, Supplier<? extends T> supplier);
static Array<Integer> range(int from, int toExclusive);
static Array<Integer> rangeClosed(int from, int toInclusive);
// Indexed access (O(1))
T get(int index); // Direct array access
Array<T> update(int index, T element); // Create new array with updated element
// Modification operations (create new array)
Array<T> append(T element);
Array<T> appendAll(Iterable<? extends T> elements);
Array<T> prepend(T element);
Array<T> prependAll(Iterable<? extends T> elements);
Array<T> insert(int index, T element);
Array<T> insertAll(int index, Iterable<? extends T> elements);
Array<T> remove(T element);
Array<T> removeAt(int index);
Array<T> removeAll(Iterable<? extends T> elements);
// Transformation operations
<U> Array<U> map(Function<? super T, ? extends U> mapper);
Array<T> filter(Predicate<? super T> predicate);
<U> Array<U> flatMap(Function<? super T, ? extends Iterable<? extends U>> mapper);
Array<T> distinct();
Array<T> distinctBy(Comparator<? super T> comparator);
Array<T> sorted();
Array<T> sorted(Comparator<? super T> comparator);
// Subsequence operations
Array<T> slice(int beginIndex, int endIndex);
Array<T> take(int n);
Array<T> drop(int n);
Array<T> takeWhile(Predicate<? super T> predicate);
Array<T> dropWhile(Predicate<? super T> predicate);
Array<T> reverse();
// Conversion operations
Object[] toJavaArray(); // Direct array access
T[] toJavaArray(Class<T> componentType); // Typed array conversion
java.util.List<T> toJavaList();
// Zipping operations
<U> Array<Tuple2<T, U>> zip(Iterable<? extends U> that);
<U, R> Array<R> zipWith(Iterable<? extends U> that, BiFunction<? super T, ? super U, ? extends R> mapper);
Array<Tuple2<T, Integer>> zipWithIndex();
}Usage Examples:
import io.vavr.collection.Array;
// Creating arrays
Array<Integer> empty = Array.empty();
Array<Integer> numbers = Array.of(1, 2, 3, 4, 5);
Array<String> words = Array.of("hello", "world", "vavr");
// O(1) indexed access (advantage over List)
Integer third = numbers.get(2); // 3 (no traversal needed)
Array<Integer> updated = numbers.update(1, 10); // [1, 10, 3, 4, 5]
// Functional operations
Array<Integer> doubled = numbers.map(x -> x * 2);
Array<Integer> evens = numbers.filter(x -> x % 2 == 0);
Array<String> lengths = words.map(w -> "Length: " + w.length());
// Array-specific operations
Array<Integer> range = Array.range(1, 6); // [1, 2, 3, 4, 5]
Array<String> filled = Array.fill(3, "test"); // ["test", "test", "test"]
// Efficient bulk operations
Array<Integer> extended = numbers.appendAll(Array.of(6, 7, 8));
Array<Integer> combined = Array.of(0).prependAll(numbers);
// Direct conversion to Java arrays (efficient)
Integer[] javaArray = numbers.toJavaArray(Integer.class);
Object[] objectArray = numbers.toJavaArray();
// Sorting (creates new array)
Array<String> sorted = words.sorted();
Array<Integer> descending = numbers.sorted((a, b) -> b.compareTo(a));
// Memory-efficient operations
Array<Integer> slice = numbers.slice(1, 4); // [2, 3, 4]
Array<Integer> first3 = numbers.take(3); // [1, 2, 3]
Array<Integer> skip2 = numbers.drop(2); // [3, 4, 5]
// Pattern matching style operations
String describe = numbers.isEmpty() ? "empty" :
numbers.size() == 1 ? "single" :
"array of " + numbers.size() + " elements";Array is particularly useful when you need:
Hash-based immutable map implementation with efficient key-value operations.
/**
* Immutable hash-based map with O(1) expected time operations
*/
class HashMap<K, V> implements Map<K, V> {
// Factory methods
static <K, V> HashMap<K, V> empty();
static <K, V> HashMap<K, V> of(K key, V value);
static <K, V> HashMap<K, V> of(K k1, V v1, K k2, V v2);
// ... up to 10 key-value pairs
static <K, V> HashMap<K, V> ofEntries(Tuple2<? extends K, ? extends V>... entries);
static <K, V> HashMap<K, V> ofEntries(Iterable<? extends Tuple2<? extends K, ? extends V>> entries);
// Map operations
Option<V> get(K key); // Get value for key
V getOrElse(K key, V defaultValue); // Get value or default
boolean containsKey(K key); // Check if key exists
boolean containsValue(V value); // Check if value exists
// Modification operations (return new HashMap)
HashMap<K, V> put(K key, V value); // Add/update key-value pair
HashMap<K, V> put(Tuple2<? extends K, ? extends V> entry);
HashMap<K, V> putAll(Iterable<? extends Tuple2<? extends K, ? extends V>> entries);
HashMap<K, V> remove(K key); // Remove key-value pair
HashMap<K, V> removeAll(Iterable<? extends K> keys);
// Transformation operations
<K2, V2> HashMap<K2, V2> map(BiFunction<? super K, ? super V, Tuple2<K2, V2>> mapper);
<V2> HashMap<K, V2> mapValues(Function<? super V, ? extends V2> mapper);
HashMap<K, V> filter(BiPredicate<? super K, ? super V> predicate);
HashMap<K, V> filterKeys(Predicate<? super K> predicate);
HashMap<K, V> filterValues(Predicate<? super V> predicate);
// Collection views
Set<K> keySet(); // Get all keys
Traversable<V> values(); // Get all values
Set<Tuple2<K, V>> entrySet(); // Get all key-value pairs
// Merging operations
HashMap<K, V> merge(Map<? extends K, ? extends V> that);
<U, R> HashMap<K, R> merge(Map<? extends K, ? extends U> that,
BiFunction<? super V, ? super U, ? extends R> collisionResolution);
}Usage Examples:
import io.vavr.collection.HashMap;
import io.vavr.collection.Map;
import io.vavr.Tuple;
// Creating maps
Map<String, Integer> scores = HashMap.of(
"Alice", 95,
"Bob", 87,
"Charlie", 92
);
// Map operations
Integer aliceScore = scores.get("Alice").getOrElse(0);
boolean hasAlice = scores.containsKey("Alice");
// Adding/updating entries
Map<String, Integer> updated = scores.put("David", 89);
Map<String, Integer> incremented = scores.mapValues(score -> score + 5);
// Filtering
Map<String, Integer> highScores = scores.filter((name, score) -> score > 90);
Map<String, Integer> aNames = scores.filterKeys(name -> name.startsWith("A"));
// Working with entries
scores.forEach((name, score) ->
System.out.println(name + ": " + score));
// Converting between representations
java.util.Map<String, Integer> javaMap = scores.toJavaMap();Hash-based immutable set implementation with efficient membership testing and set operations.
/**
* Immutable hash-based set with O(1) expected time operations
*/
class HashSet<T> implements Set<T> {
// Factory methods
static <T> HashSet<T> empty();
static <T> HashSet<T> of(T element);
static <T> HashSet<T> of(T... elements);
static <T> HashSet<T> ofAll(Iterable<? extends T> elements);
// Set operations
boolean contains(T element); // Test membership
HashSet<T> add(T element); // Add element
HashSet<T> addAll(Iterable<? extends T> elements);
HashSet<T> remove(T element); // Remove element
HashSet<T> removeAll(Iterable<? extends T> elements);
// Set algebra operations
HashSet<T> union(Set<? extends T> that); // Union (A ∪ B)
HashSet<T> intersect(Set<? extends T> that); // Intersection (A ∩ B)
HashSet<T> diff(Set<? extends T> that); // Difference (A - B)
// Transformation operations
<U> HashSet<U> map(Function<? super T, ? extends U> mapper);
HashSet<T> filter(Predicate<? super T> predicate);
<U> HashSet<U> flatMap(Function<? super T, ? extends Iterable<? extends U>> mapper);
// Subset operations
boolean isSubsetOf(Set<? extends T> that);
boolean isProperSubsetOf(Set<? extends T> that);
}Lazy evaluation sequence that can represent infinite collections with on-demand computation.
/**
* Lazy infinite sequence with on-demand evaluation
*/
class Stream<T> implements LinearSeq<T> {
// Factory methods
static <T> Stream<T> empty();
static <T> Stream<T> of(T... elements);
static <T> Stream<T> ofAll(Iterable<? extends T> elements);
static <T> Stream<T> continually(T element); // Infinite constant stream
static <T> Stream<T> continually(Supplier<? extends T> supplier); // Infinite generated stream
static <T> Stream<T> iterate(T seed, Function<? super T, ? extends T> f); // Infinite iteration
static Stream<Integer> from(int start); // Infinite arithmetic progression
static Stream<Integer> range(int from, int toExclusive); // Finite range
// Stream operations (lazy)
T head(); // First element (evaluated)
Stream<T> tail(); // Rest of stream (lazy)
boolean isEmpty(); // Check if stream is empty
// Transformation operations (lazy)
<U> Stream<U> map(Function<? super T, ? extends U> mapper);
Stream<T> filter(Predicate<? super T> predicate);
<U> Stream<U> flatMap(Function<? super T, ? extends Iterable<? extends U>> mapper);
Stream<T> distinct();
// Limiting operations (finite results)
Stream<T> take(int n); // Take first n elements
Stream<T> takeWhile(Predicate<? super T> predicate); // Take while condition holds
Stream<T> drop(int n); // Skip first n elements
Stream<T> dropWhile(Predicate<? super T> predicate); // Skip while condition holds
// Terminal operations (force evaluation)
List<T> toList(); // Convert to List (forces evaluation)
Vector<T> toVector(); // Convert to Vector
T reduce(BinaryOperator<T> op); // Reduce to single value
<U> U foldLeft(U zero, BiFunction<? super U, ? super T, ? extends U> combine);
// Zipping operations
<U> Stream<Tuple2<T, U>> zip(Iterable<? extends U> that);
Stream<Tuple2<T, Integer>> zipWithIndex();
}Usage Examples:
import io.vavr.collection.Stream;
import io.vavr.collection.List;
// Infinite streams
Stream<Integer> naturals = Stream.from(1); // 1, 2, 3, 4, ...
Stream<Integer> evens = naturals.filter(x -> x % 2 == 0); // 2, 4, 6, 8, ...
Stream<Integer> powers = Stream.iterate(1, x -> x * 2); // 1, 2, 4, 8, 16, ...
// Taking finite portions
List<Integer> first10Evens = evens.take(10).toList();
List<Integer> powersUpTo1000 = powers.takeWhile(x -> x <= 1000).toList();
// Lazy evaluation demonstration
Stream<String> expensive = Stream.continually(() -> {
System.out.println("Computing...");
return "expensive";
});
// Nothing printed yet - computation is lazy
Stream<String> transformed = expensive.map(String::toUpperCase);
// Still nothing printed - still lazy
String first = transformed.head(); // Now prints "Computing..." once
// Fibonacci sequence example
Stream<Integer> fibonacci = Stream.of(1, 1)
.appendSelf(self -> self.zip(self.tail()).map(t -> t._1() + t._2()));
List<Integer> first10Fib = fibonacci.take(10).toList(); // [1,1,2,3,5,8,13,21,34,55]Additional collection types for specific use cases.
/**
* Character sequence with string-like operations
*/
class CharSeq implements IndexedSeq<Character> {
static CharSeq empty();
static CharSeq of(String string);
static CharSeq of(char... chars);
// String-like operations
char charAt(int index);
CharSeq substring(int beginIndex);
CharSeq substring(int beginIndex, int endIndex);
List<CharSeq> split(String delimiter);
CharSeq replace(char oldChar, char newChar);
CharSeq toLowerCase();
CharSeq toUpperCase();
CharSeq trim();
// Conversion
String mkString();
char[] toCharArray();
}
/**
* FIFO queue interface
*/
interface Queue<T> extends Traversable<T> {
static <T> Queue<T> empty();
static <T> Queue<T> of(T... elements);
T peek(); // Get front element without removing
Option<T> peekOption(); // Safe peek operation
Queue<T> enqueue(T element); // Add to rear
Tuple2<T, Queue<T>> dequeue(); // Remove from front, return element and new queue
Option<Tuple2<T, Queue<T>>> dequeueOption(); // Safe dequeue operation
}
/**
* Priority queue with heap-based implementation
*/
class PriorityQueue<T> implements Queue<T> {
static <T extends Comparable<? super T>> PriorityQueue<T> empty();
static <T> PriorityQueue<T> empty(Comparator<? super T> comparator);
static <T extends Comparable<? super T>> PriorityQueue<T> of(T... elements);
// Priority queue specific operations
T peek(); // Get highest priority element
PriorityQueue<T> enqueue(T element); // Add element maintaining heap property
Tuple2<T, PriorityQueue<T>> dequeue(); // Remove highest priority element
// Merge operation
PriorityQueue<T> merge(PriorityQueue<T> that);
}
/**
* Compact set for non-negative integers
*/
class BitSet implements SortedSet<Integer> {
static BitSet empty();
static BitSet of(int... ints);
static BitSet ofAll(Iterable<Integer> ints);
// BitSet specific operations
BitSet add(int value); // Add integer to set
BitSet remove(int value); // Remove integer from set
BitSet union(BitSet that); // Bitwise OR
BitSet intersect(BitSet that); // Bitwise AND
BitSet complement(); // Bitwise NOT (finite range)
// Range operations
static BitSet range(int from, int toExclusive);
int min(); // Smallest element
int max(); // Largest element
}Install with Tessl CLI
npx tessl i tessl/maven-io-vavr--vavr