CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-io-vavr--vavr

Object-functional language extension to Java 8+ providing persistent collections, functional abstractions, and monadic control types.

Pending
Overview
Eval results
Files

concurrent.mddocs/

Concurrent Programming

Asynchronous programming utilities with Futures, Promises, and functional composition for building concurrent and reactive applications.

Capabilities

Future - Asynchronous Computations

Represents the result of an asynchronous computation that may complete with a value, fail with an exception, or be cancelled.

/**
 * Asynchronous computation result that may complete with success or failure
 */
interface Future<T> extends Value<T> {
    // Factory methods
    static <T> Future<T> of(Executor executor, CheckedFunction0<? extends T> computation);
    static <T> Future<T> of(CheckedFunction0<? extends T> computation);  // Uses ForkJoinPool
    static <T> Future<T> successful(T value);                           // Immediately completed Future
    static <T> Future<T> failed(Throwable exception);                   // Immediately failed Future
    static <T> Future<T> fromTry(Try<? extends T> result);             // Create from Try
    static <T> Future<T> fromCompletableFuture(CompletableFuture<T> future);
    
    // Completion state
    boolean isCompleted();                     // true if computation finished (success or failure)
    boolean isSuccess();                       // true if completed successfully
    boolean isFailure();                       // true if completed with exception
    boolean isCancelled();                     // true if computation was cancelled
    
    // Value access (blocking operations)
    T get();                                   // Block until completion, return value or throw
    T get(long timeout, TimeUnit unit);       // Block with timeout
    Option<Try<T>> getValue();                 // Non-blocking: get current value if completed
    
    // Transformation operations
    <U> Future<U> map(Function<? super T, ? extends U> mapper);
    <U> Future<U> mapTry(CheckedFunction1<? super T, ? extends U> mapper);
    <U> Future<U> flatMap(Function<? super T, ? extends Future<? extends U>> mapper);
    
    // Error handling
    Future<T> recover(Function<? super Throwable, ? extends T> recovery);
    Future<T> recoverWith(Function<? super Throwable, ? extends Future<? extends T>> recovery);
    
    // Filtering
    Future<T> filter(Predicate<? super T> predicate);
    Future<T> filterTry(CheckedPredicate<? super T> predicate);
    
    // Side effects (non-blocking callbacks)
    Future<T> onComplete(Consumer<? super Try<T>> action);
    Future<T> onSuccess(Consumer<? super T> action);           // Called if successful
    Future<T> onFailure(Consumer<? super Throwable> action);   // Called if failed
    
    // Combining Futures
    <U> Future<Tuple2<T, U>> zip(Future<? extends U> that);
    <U, R> Future<R> zipWith(Future<? extends U> that, BiFunction<? super T, ? super U, ? extends R> mapper);
    Future<T> fallbackTo(Future<? extends T> that);            // Use that if this fails
    
    // Conversion operations
    CompletableFuture<T> toCompletableFuture();
    Try<T> toTry();                            // Blocks until completion
    
    // Executor information
    Executor executor();                       // Get the executor used for this Future
    
    // Cancellation
    void cancel();                            // Cancel the computation if not completed
    void cancel(boolean mayInterruptIfRunning);
}

Usage Examples:

import io.vavr.concurrent.Future;
import io.vavr.control.Try;
import java.util.concurrent.Executors;

// Creating Futures
Future<String> immediate = Future.successful("Hello");
Future<Integer> computation = Future.of(() -> expensiveComputation());
Future<String> withExecutor = Future.of(
    Executors.newCachedThreadPool(),
    () -> downloadData("http://example.com")
);

// Transforming Futures
Future<String> processed = computation
    .map(i -> "Result: " + i)
    .recover(ex -> "Error: " + ex.getMessage());

// Chaining asynchronous operations
Future<String> chained = Future.of(() -> getUserId())
    .flatMap(id -> Future.of(() -> fetchUserName(id)))
    .flatMap(name -> Future.of(() -> fetchUserEmail(name)));

// Combining multiple Futures
Future<String> name = Future.of(() -> "John");
Future<Integer> age = Future.of(() -> 30);
Future<String> person = name.zipWith(age, (n, a) -> n + " is " + a + " years old");

// Error handling
Future<String> safe = Future.of(() -> riskyOperation())
    .recover(throwable -> "Default value")
    .onFailure(ex -> System.err.println("Operation failed: " + ex));

// Non-blocking callbacks
computation
    .onSuccess(result -> System.out.println("Got: " + result))
    .onFailure(error -> System.err.println("Failed: " + error))
    .onComplete(tryResult -> System.out.println("Completed: " + tryResult));

// Fallback pattern
Future<String> primary = Future.of(() -> primaryService());
Future<String> backup = Future.of(() -> backupService());
Future<String> resilient = primary.fallbackTo(backup);

// Converting to Java types
CompletableFuture<Integer> javaFuture = computation.toCompletableFuture();

// Helper methods
static int expensiveComputation() throws InterruptedException {
    Thread.sleep(1000);
    return 42;
}

static String downloadData(String url) throws IOException {
    // Simulate download
    return "Downloaded from " + url;
}

Promise - Completable Future

A Promise is a writable, single-assignment container that completes a Future. Used for bridging callback-based APIs to Future-based APIs.

/**
 * Completable container that provides a Future and allows completing it exactly once
 */
interface Promise<T> {
    // Factory methods
    static <T> Promise<T> make();              // Create new Promise
    static <T> Promise<T> make(Executor executor); // Create with specific executor
    static <T> Promise<T> successful(T value); // Create already completed Promise
    static <T> Promise<T> failed(Throwable exception); // Create already failed Promise
    
    // Completion operations (can only be called once)
    Promise<T> success(T value);               // Complete with success value
    Promise<T> failure(Throwable exception);   // Complete with failure
    Promise<T> complete(Try<? extends T> result); // Complete with Try result
    Promise<T> completeWith(Future<? extends T> other); // Complete when other completes
    
    // Try completion operations (return false if already completed)
    boolean trySuccess(T value);               // Try to complete with success
    boolean tryFailure(Throwable exception);   // Try to complete with failure
    boolean tryComplete(Try<? extends T> result); // Try to complete with Try
    boolean tryCompleteWith(Future<? extends T> other); // Try to complete with other Future
    
    // State checking
    boolean isCompleted();                     // Check if Promise has been completed
    
    // Future access
    Future<T> future();                        // Get the Future backed by this Promise
}

Usage Examples:

import io.vavr.concurrent.Promise;
import io.vavr.concurrent.Future;
import io.vavr.control.Try;

// Basic Promise usage
Promise<String> promise = Promise.make();
Future<String> future = promise.future();

// Complete the promise in another thread
new Thread(() -> {
    try {
        Thread.sleep(1000);
        promise.success("Hello from another thread!");
    } catch (InterruptedException e) {
        promise.failure(e);
    }
}).start();

// Use the future
future.onSuccess(result -> System.out.println("Got: " + result));

// Bridging callback API to Future API
public Future<String> callbackToFuture(CallbackAPI api) {
    Promise<String> promise = Promise.make();
    
    api.doSomethingAsync(new Callback<String>() {
        @Override
        public void onSuccess(String result) {
            promise.success(result);
        }
        
        @Override
        public void onFailure(Exception error) {
            promise.failure(error);
        }
    });
    
    return promise.future();
}

// Try completion (safe for multiple calls)
Promise<Integer> safePromise = Promise.make();
boolean completed1 = safePromise.trySuccess(42);    // true
boolean completed2 = safePromise.trySuccess(24);    // false - already completed

// Completing with Try
Try<String> result = Try.of(() -> someOperation());
Promise<String> promiseFromTry = Promise.make();
promiseFromTry.complete(result);

// Promise chaining
Promise<String> step1 = Promise.make();
Future<Integer> pipeline = step1.future()
    .map(String::length)
    .filter(len -> len > 5);

step1.success("Hello World");

Task - Lazy Asynchronous Computation

Represents a lazy asynchronous computation that is not started until explicitly run, allowing for composable and reusable async operations.

/**
 * Lazy asynchronous computation that starts only when run
 */
class Task<T> implements Value<T> {
    // Factory methods
    static <T> Task<T> of(CheckedFunction0<? extends T> computation);
    static <T> Task<T> of(Executor executor, CheckedFunction0<? extends T> computation);
    static <T> Task<T> successful(T value);    // Task that immediately succeeds
    static <T> Task<T> failed(Throwable exception); // Task that immediately fails
    static <T> Task<T> fromTry(Try<? extends T> result);
    static <T> Task<T> async(CheckedFunction0<? extends T> computation); // Always async
    
    // Execution
    Future<T> run();                           // Execute the task and return Future
    Future<T> run(Executor executor);          // Execute with specific executor
    
    // Transformation operations (lazy)
    <U> Task<U> map(Function<? super T, ? extends U> mapper);
    <U> Task<U> mapTry(CheckedFunction1<? super T, ? extends U> mapper);
    <U> Task<U> flatMap(Function<? super T, ? extends Task<? extends U>> mapper);
    
    // Error handling (lazy)
    Task<T> recover(Function<? super Throwable, ? extends T> recovery);
    Task<T> recoverWith(Function<? super Throwable, ? extends Task<? extends T>> recovery);
    
    // Filtering (lazy)
    Task<T> filter(Predicate<? super T> predicate);
    Task<T> filterTry(CheckedPredicate<? super T> predicate);
    
    // Combining tasks (lazy)
    <U> Task<Tuple2<T, U>> zip(Task<? extends U> that);
    <U, R> Task<R> zipWith(Task<? extends U> that, BiFunction<? super T, ? super U, ? extends R> mapper);
    Task<T> fallbackTo(Task<? extends T> that);
    
    // Side effects (applied when task runs)
    Task<T> peek(Consumer<? super T> action);
    Task<T> onFailure(Consumer<? super Throwable> action);
    
    // Conversion operations
    Future<T> toFuture();                      // Same as run()
    Try<T> toTry();                           // Run synchronously
    
    // Utility operations
    Task<T> timeout(long timeout, TimeUnit unit);
    Task<T> timeout(long timeout, TimeUnit unit, Supplier<? extends T> fallback);
    Task<T> delay(long delay, TimeUnit unit);  // Delay execution
}

Usage Examples:

import io.vavr.concurrent.Task;
import io.vavr.concurrent.Future;
import java.util.concurrent.TimeUnit;

// Creating Tasks (lazy - not executed yet)
Task<String> fetchData = Task.of(() -> downloadData("http://api.example.com"));
Task<Integer> compute = Task.of(() -> heavyComputation());
Task<String> immediate = Task.successful("Already computed");

// Transforming Tasks (still lazy)
Task<String> processed = compute
    .map(result -> "Result: " + result)
    .recover(ex -> "Error: " + ex.getMessage());

// Chaining Tasks (lazy composition)
Task<String> pipeline = Task.of(() -> getUserId())
    .flatMap(id -> Task.of(() -> fetchUserData(id)))
    .flatMap(data -> Task.of(() -> processUserData(data)));

// Combining multiple Tasks
Task<String> name = Task.of(() -> fetchUserName());
Task<Integer> age = Task.of(() -> fetchUserAge());
Task<String> profile = name.zipWith(age, (n, a) -> n + " (" + a + " years old)");

// Adding delays and timeouts
Task<String> delayed = fetchData.delay(5, TimeUnit.SECONDS);
Task<String> withTimeout = fetchData.timeout(10, TimeUnit.SECONDS, () -> "Timeout fallback");

// Fallback Tasks
Task<String> primary = Task.of(() -> primaryService());
Task<String> backup = Task.of(() -> backupService());
Task<String> resilient = primary.fallbackTo(backup);

// Execution (this is when computation actually starts)
Future<String> future1 = processed.run();                    // Run with default executor
Future<String> future2 = processed.run(customExecutor);      // Run with custom executor
Try<String> syncResult = processed.toTry();                  // Run synchronously

// Reusable Tasks
Task<List<String>> reusableTask = Task.of(() -> fetchDataList());
Future<List<String>> execution1 = reusableTask.run();        // First execution
Future<List<String>> execution2 = reusableTask.run();        // Second execution (independent)

// Error handling in lazy context
Task<String> safeTask = Task.of(() -> riskyOperation())
    .recover(throwable -> "Fallback value")
    .onFailure(ex -> logger.error("Task failed", ex));

// Helper methods
static String downloadData(String url) throws IOException {
    // Simulate download
    Thread.sleep(2000);
    return "Data from " + url;
}

static Integer heavyComputation() throws InterruptedException {
    Thread.sleep(5000);
    return 42;
}

Utility Classes and Static Methods

Helper methods for working with concurrent operations and multiple Futures.

/**
 * Utility methods for Future operations
 */
class Future {
    // Sequence operations - convert List<Future<T>> to Future<List<T>>
    static <T> Future<Seq<T>> sequence(Iterable<? extends Future<? extends T>> futures);
    static <T> Future<List<T>> sequence(List<? extends Future<? extends T>> futures);
    
    // Traverse operations - map and sequence combined
    static <T, U> Future<Seq<U>> traverse(Iterable<? extends T> values, 
                                          Function<? super T, ? extends Future<? extends U>> mapper);
    
    // Reduce operations
    static <T> Future<T> reduce(Iterable<? extends Future<? extends T>> futures, 
                               BinaryOperator<T> op);
    static <T> Future<Option<T>> reduceOption(Iterable<? extends Future<? extends T>> futures, 
                                             BinaryOperator<T> op);
    
    // Find operations  
    static <T> Future<Option<T>> find(Iterable<? extends Future<? extends T>> futures,
                                     Predicate<? super T> predicate);
    
    // Race operations - return first completed Future
    static <T> Future<T> firstCompletedOf(Iterable<? extends Future<? extends T>> futures);
    
    // Timing operations
    static Future<Void> delay(long delay, TimeUnit unit);
    static <T> Future<T> timeout(Future<T> future, long timeout, TimeUnit unit);
    static <T> Future<T> timeout(Future<T> future, long timeout, TimeUnit unit, 
                                Supplier<? extends T> fallback);
}

/**
 * Utility methods for Promise operations
 */
class Promise {
    // Create Promise from callback-style API
    static <T> Promise<T> fromCallback(Consumer<Consumer<T>> callbackConsumer);
    static <T> Promise<T> fromCallback(Consumer<BiConsumer<T, Throwable>> callbackConsumer);
}

Usage Examples:

import io.vavr.concurrent.Future;
import io.vavr.collection.List;
import java.util.concurrent.TimeUnit;

// Sequence operations - wait for all Futures to complete
List<Future<String>> futures = List.of(
    Future.of(() -> fetchData("url1")),
    Future.of(() -> fetchData("url2")), 
    Future.of(() -> fetchData("url3"))
);

Future<List<String>> allResults = Future.sequence(futures);
allResults.onSuccess(results -> 
    System.out.println("All completed: " + results));

// Traverse - transform and collect
List<String> urls = List.of("url1", "url2", "url3");
Future<List<String>> traverseResult = Future.traverse(urls, url -> 
    Future.of(() -> fetchData(url)));

// Race - get first completed
Future<String> fastest = Future.firstCompletedOf(futures);
fastest.onSuccess(result -> 
    System.out.println("First completed: " + result));

// Reduce - combine all results
Future<String> combined = Future.reduce(futures, (a, b) -> a + ", " + b);

// Find - get first result matching predicate
Future<Option<String>> found = Future.find(futures, 
    result -> result.contains("important"));

// Timing operations
Future<Void> delayed = Future.delay(5, TimeUnit.SECONDS);
Future<String> withDeadline = Future.timeout(
    Future.of(() -> slowOperation()),
    10, TimeUnit.SECONDS,
    () -> "Timeout occurred"
);

// Promise from callback API
Promise<String> callbackPromise = Promise.fromCallback(callback -> {
    legacyAsyncAPI("param", new LegacyCallback() {
        @Override
        public void onResult(String result) {
            callback.accept(result);
        }
        
        @Override
        public void onError(Exception error) {
            // Handle error case
        }
    });
});

Install with Tessl CLI

npx tessl i tessl/maven-io-vavr--vavr

docs

collections.md

concurrent.md

control-types.md

core-types.md

functional-interfaces.md

index.md

tile.json