A production-grade multiplatform functional programming library providing Scala-like Option[T] and IO[T] monads for Java, Kotlin, JavaScript, and Native platforms.
Quick Start | API Docs | Contributing
Java's Optional was designed as a return type for "no value," but lacks the composability of Scala's Option. More critically, Java has no native equivalent to Scala's IO monad for lazy, composable side-effect management. This library bridges that gap with:
- β Zero external dependencies - Uses only JDK/stdlib
- β Tiny footprint - ~400 LOC of production code
- β Multiplatform - JVM, JS, Native-ready
- β Both Java AND Kotlin APIs - Idiomatic for each language
- β Production-ready - 98.46% test coverage, 0 PMD violations
- β Java 17+ (LTS) - Modern, long-term support version
| Metric | Requirement | Actual | Status |
|---|---|---|---|
| Test Coverage | β₯90% | 98.46% | β EXCEEDED |
| PMD Violations | 0 | 0 | β PERFECT |
| Build Status | Success | Success | β PASSING |
| Test Count | Comprehensive | 106 tests | β ALL PASSING |
| Multiplatform Tests | JVM + JS | 158 tests | β ALL PASSING |
This library is published to Maven Central under the com.brentzey.functional namespace.
// build.gradle.kts
kotlin {
jvm()
js(IR) { browser(); nodejs() }
linuxX64()
macosArm64()
// ... other targets
sourceSets {
val commonMain by getting {
dependencies {
// Single dependency - Gradle auto-resolves platform artifacts
implementation("com.brentzey.functional:jvm-functional-utils:1.0.0")
}
}
}
}// Gradle Kotlin DSL
dependencies {
implementation("com.brentzey.functional:jvm-functional-utils-jvm:1.0.0")
}// Gradle Groovy
dependencies {
implementation 'com.brentzey.functional:jvm-functional-utils-jvm:1.0.0'
}<!-- Maven -->
<dependency>
<groupId>com.brentzey.functional</groupId>
<artifactId>jvm-functional-utils-jvm</artifactId>
<version>1.0.0</version>
</dependency>dependencies {
implementation("com.brentzey.functional:jvm-functional-utils-js:1.0.0")
}All artifacts are published to Maven Central:
| Platform | Artifact ID | Use Case |
|---|---|---|
| Multiplatform Root | jvm-functional-utils |
KMP projects (auto-resolves platforms) |
| JVM/Android | jvm-functional-utils-jvm |
JVM/Android applications |
| JavaScript | jvm-functional-utils-js |
JavaScript/Node.js applications |
| Linux Native | jvm-functional-utils-linuxX64 |
Linux native applications |
| macOS Intel | jvm-functional-utils-macosX64 |
macOS x64 native applications |
| macOS ARM | jvm-functional-utils-macosArm64 |
Apple Silicon (M1/M2/M3) applications |
| Windows | jvm-functional-utils-mingwX64 |
Windows native applications |
Browse on Maven Central: https://central.sonatype.com/artifact/com.brentzey.functional/jvm-functional-utils
Avoid the "pyramid of doom" when combining multiple Optional values:
import com.brentzey.functional.OptionalUtils;
import java.util.Optional;
// β Before: Nested flatMaps
Optional<User> result = getFirstName().flatMap(first ->
getLastName().flatMap(last ->
getEmail().map(email ->
new User(first, last, email)
)
)
);
// β
After: Clean composition
Optional<User> result = OptionalUtils.zip(
getFirstName(),
getLastName(),
getEmail(),
(first, last, email) -> new User(first, last, email)
);Available Methods:
zip(Optional<A>, Optional<B>, BiFunction)- Combine 2 optionalszip(Optional<A>, Optional<B>, Optional<C>, TriFunction)- Combine 3 optionalssequence(Collection<Optional<T>>)- All-or-nothing list conversionfold(Optional<T>, Supplier, Function)- Functional if-else with return value
Stop swallowing exceptions with Optional. Use IO for networking and side effects:
import com.brentzey.functional.JavaIO;
// Define lazy operations (nothing executes yet)
JavaIO<String> fetchToken = JavaIO.of(() -> authService.getToken());
// Chain operations (still lazy)
JavaIO<User> workflow = fetchToken
.flatMap(token -> JavaIO.of(() -> apiClient.getUser(token)))
.map(user -> enrichUser(user));
// Execute safely
Optional<User> result = workflow.runToOptional(); // Returns Optional.empty() on error
// Or throw if you need the exception
User user = workflow.unsafeRunSync(); // Throws IOExecutionException on error
// Or get detailed error information
JavaIO.Result<User> result = workflow.attempt();
if (result.isSuccess()) {
User user = result.value();
} else {
Exception error = result.error();
}Why IO instead of Optional?
- β Preserves stack traces (Optional swallows them)
- β Lazy evaluation (runs only when explicitly executed)
- β Composable chains (map, flatMap)
- β Wraps checked exceptions automatically
import com.brentzey.functional.OptionUtils
// Combine nullable values
val fullName: String? = OptionUtils.zip(
getFirstName(),
getLastName()
) { first, last -> "$first $last" }
// All-or-nothing sequence
val allIds: List<String>? = OptionUtils.sequence(
listOf(getId1(), getId2(), getId3())
)
// Functional fold
val message = OptionUtils.fold(
getUserName(),
ifNull = { "Guest" },
ifNotNull = { "Hello, $it" }
)import com.brentzey.functional.IO
// Define lazy computation
val fetchToken = IO.of { authService.getToken() }
// Chain operations
val workflow = fetchToken
.flatMap { token -> IO.of { apiClient.getUser(token) } }
.map { user -> enrichUser(user) }
// Execute
val result: User? = workflow.runToNullable()
// Or use Result type
when (val result = workflow.attempt()) {
is IO.Result.Success -> println("User: ${result.value}")
is IO.Result.Failure -> println("Error: ${result.error}")
}You need to:
- Fetch an auth token
- Get user details
- Load user profile (can fail)
- Load user settings (can fail)
- Combine everything, or fail if anything goes wrong
public User loadUser(String id) {
try {
String token = authService.getToken();
try {
User user = apiClient.getUser(token, id);
try {
Profile profile = apiClient.getProfile(user.id);
try {
Settings settings = apiClient.getSettings(user.id);
return enrichUser(user, profile, settings);
} catch (Exception e) {
logger.error("Failed to load settings", e);
throw e;
}
} catch (Exception e) {
logger.error("Failed to load profile", e);
throw e;
}
} catch (Exception e) {
logger.error("Failed to load user", e);
throw e;
}
} catch (Exception e) {
logger.error("Failed to get token", e);
throw e;
}
}public Optional<User> loadUser(String id) {
return JavaIO.of(() -> authService.getToken())
.flatMap(token -> JavaIO.of(() -> apiClient.getUser(token, id)))
.flatMap(user -> {
var profile = JavaIO.of(() -> apiClient.getProfile(user.id)).runToOptional();
var settings = JavaIO.of(() -> apiClient.getSettings(user.id)).runToOptional();
return OptionalUtils.zip(profile, settings, (p, s) ->
JavaIO.pure(enrichUser(user, p, s))
).orElse(JavaIO.pure(null));
})
.runToOptional();
}Benefits:
- 90% less boilerplate
- Composable and chainable
- Automatic exception handling
- Lazy evaluation
- Easy to test (mock each IO independently)
| Method | Description | Example |
|---|---|---|
zip(a, b, fn) |
Combine 2 optionals | zip(Optional.of(1), Optional.of(2), (x,y) -> x+y) |
zip(a, b, c, fn) |
Combine 3 optionals | zip(a, b, c, (x,y,z) -> x+y+z) |
sequence(list) |
List<Optional> β Optional<List> | sequence(List.of(Optional.of(1), Optional.of(2))) |
fold(opt, ifEmpty, ifPresent) |
Functional if-else | fold(opt, () -> 0, x -> x * 2) |
| Method | Description | Returns |
|---|---|---|
of(() -> T) |
Wrap computation | JavaIO<T> |
pure(T) |
Wrap pure value | JavaIO<T> |
map(fn) |
Transform result | JavaIO<R> |
flatMap(fn) |
Chain IO operation | JavaIO<R> |
runToOptional() |
Execute safely | Optional<T> |
unsafeRunSync() |
Execute, throw on error | T |
attempt() |
Execute, return Result | Result<T> |
| Method | Description | Example |
|---|---|---|
zip(a, b, fn) |
Combine 2 nullables | zip(1, 2) { x, y -> x + y } |
zip(a, b, c, fn) |
Combine 3 nullables | zip(a, b, c) { x, y, z -> x + y + z } |
sequence(list) |
List<T?> β List? | sequence(listOf(1, 2, 3)) |
fold(value, ifNull, ifNotNull) |
Functional if-else | fold(value, { 0 }, { it * 2 }) |
| Method | Description | Returns |
|---|---|---|
of { T } |
Wrap computation | IO<T> |
pure(T) |
Wrap pure value | IO<T> |
map { R } |
Transform result | IO<R> |
flatMap { IO<R> } |
Chain IO operation | IO<R> |
runToNullable() |
Execute safely | T? |
unsafeRunSync() |
Execute, throw on error | T |
attempt() |
Execute, return Result | Result<T> |
This library adheres to the strictest production standards:
| Component | Tests | Coverage |
|---|---|---|
| OptionalUtils (Java) | 25 | ~100% |
| JavaIO | 29 | ~98% |
| OptionUtils (Kotlin) | 24 | ~100% |
| IO (Kotlin) | 28 | ~98% |
| Total | 106 | 98.46% |
- Tool: PMD 7.0.0
- Rulesets: Best Practices, Code Style, Design, Error Prone, Multithreading, Performance, Security
- Priority: 1 (Highest)
- Result: β ZERO VIOLATIONS
- β All edge cases covered (null, empty, errors)
- β Exception path testing (checked + runtime)
- β Type safety validation
- β Behavioral testing (laziness, side effects)
- β Integration testing (complex workflows)
- β Multiplatform testing (JVM + JS)
# Run all tests and quality checks
./run-quality-checks.sh
# Or individually
./gradlew clean test # Run tests
./gradlew koverVerify # Verify 90% coverage threshold
./gradlew pmdMain # Static analysis
./gradlew koverHtmlReport # Generate coverage report
# View reports
open lib/build/reports/kover/html/index.html # Coverage report
open lib/build/reports/pmd/main.html # PMD report| Platform | Status | Notes |
|---|---|---|
| JVM | β Supported | Java 17+, Kotlin JVM |
| JavaScript | β Supported | Browser & Node.js via Kotlin/JS |
| Native (Kotlin/Native) | β Supported | Linux x64, macOS x64/ARM64, Windows x64 |
| GraalVM Native Image | β Supported | Compile JVM apps to native binaries |
The Kotlin APIs (OptionUtils, IO) work identically across all platforms. The Java APIs (OptionalUtils, JavaIO) are JVM-only.
This library is GraalVM Native Image ready! Applications using this library can be compiled to native binaries with instant startup and low memory footprint:
# Your application using jvm-functional-utils
native-image -jar your-app.jar -o your-app-native
# Result: Native binary with <50ms startup, ~10MB memory
./your-app-nativeThe library includes native-image metadata, so no additional configuration is needed.
jvm-functional-utils/
βββ lib/ # Main library module
β βββ src/
β β βββ commonMain/kotlin/ # Kotlin multiplatform code
β β β βββ com/brentzey/functional/
β β β βββ OptionUtils.kt # Nullable composition
β β β βββ IO.kt # IO monad (multiplatform)
β β βββ jvmMain/java/ # Java code
β β β βββ com/brentzey/functional/
β β β βββ OptionalUtils.java # Optional composition
β β β βββ JavaIO.java # IO monad (Java)
β β βββ commonTest/kotlin/ # Kotlin tests (run on all platforms)
β β βββ jvmTest/java/ # Java tests
β βββ build.gradle.kts # Build configuration
βββ config/pmd/ruleset.xml # PMD strict rules
βββ run-quality-checks.sh # Automated QA script
βββ README.md # This file
βββ LICENSE # MIT License
βββ CONTRIBUTING.md # Contribution guidelines
βββ .agent/ # Agent working directory (gitignored)
βββ FUNCTIONAL_UTILS_README.md # Detailed user guide
βββ EXAMPLES.md # Extended examples
βββ IMPLEMENTATION_SUMMARY.md # Technical details
βββ TESTING_REPORT.md # Full QA report
Contributions are welcome! See CONTRIBUTING.md for guidelines.
For build instructions, see BUILDING.md.
Key Requirements:
- All code must maintain β₯90% test coverage
- Zero PMD violations
- All tests must pass (JVM + JS + Native)
- Follow existing code style
- Add tests for new features
MIT License - see LICENSE for details.
Inspired by:
- Scala:
Option[T]andIO[T]monads - Cats Effect & ZIO: Functional effect systems (Scala)
- Arrow: Functional programming for Kotlin
- Vavr: Functional programming for Java
- Tiny footprint: ~400 LOC, zero runtime dependencies
- Fast compilation: < 5 seconds for full build + tests
- Zero overhead: Inline functions, no reflection
- JVM optimized: Java 17+ bytecode, HotSpot-friendly
- GraalVM Native: <50ms startup, ~10MB memory footprint
- Multiplatform: JVM, JS, Native (Linux, macOS, Windows)
- Quick Start: QUICKSTART.md - Build, test, and publish guide
- Building: BUILDING.md - Detailed build documentation
- Publishing: PUBLISHING.md - Maven Central setup
- Contributing: CONTRIBUTING.md - How to contribute
- Changelog: CHANGELOG.md - Version history
- Issue Tracker: GitHub Issues
This library follows these principles:
- Laziness by Default: IO operations don't execute until explicitly run
- Type Safety: Checked exceptions are wrapped, not swallowed
- Composability: Operations chain naturally without nesting
- Multiplatform: Write once, run anywhere (JVM, JS, Native)
- Zero Dependencies: Lightweight and focused
- Production Quality: 98.46% coverage, 0 violations, 100% passing tests
- Native Ready: GraalVM Native Image support for instant startup
Built with β€οΈ for functional programmers who want ergonomic monadic composition without heavyweight dependencies.