expressible
expressible copied to clipboard
Utility library dedicated for functional & non-functional codebases to simplify modelling of success and failure responses for Java/Kotlin 🔀
Expressible

Dependency free utility library for Java & Kotlin, dedicated for functional codebases that require enhanced response handling. Express yourself with inspired by Rust, Kotlin and Vavr wrappers, to provide better API using this tiny library.
Supported wrappers (in panda.std.*
package):
Features | Description |
---|---|
Result<Value, Error> |
solve error handling gracefully, get rid of exception based side-effects |
Option<Value> |
enhanced alternative to standard Optional<Value> |
Lazy<Value> |
lazy values & runners |
Completable<Value> with Publisher & Subscriber |
synchronized alternative to CompletableFuture<Value> |
Reference<V> , MutableReference<V> , Computed |
Simple reactive containers |
Mono<A> , Pair<A, B> , Triple<A, B, C> , Quad<A, B, C, D> |
generic wrappers for set of values |
Throwing functions, runnables, suppliers and consumers | set of functional interfaces with support for exception signatures |
Tri and Quad consumers, functions and predicates | additional functional interfaces |
PandaStream<Value> |
Stream<Value> wrapper with support for features provided by expresible library |
By default, expressible exposes non-terminating methods, so you can freely divide functions into smaller pieces and move from non-functional codebases without having a heart attack.
dependencies {
implementation("org.panda-lang:expressible:1.3.6") // Core library
implementation("org.panda-lang:expressible-kt:1.3.6") // Kotlin extensions
testImplementation("org.panda-lang:expressible-junit:1.3.6") // JUnit extensions
}
Examples
Suggested snippets show only a small use-cases for the available api. You're not forced to use this library this way, so you may need to find your style in expressing your thoughts. Adopting functional approach requires time and to simplify this process it's easier to slowly introduce new elements based on simple concepts.
Result
Rather than using Exception
based error handling, return meaningful errors and interact with api responses gracefully.
Following functional programming patterns make sure your methods don't contain side effects and unexpected exit points.
class UserEndpoint {
// You can use fully functional approach
fun createUser(request: HttpRequest, response: HttpResponse) =
userFacade.createUsername(request.param("username"))
.peek { user -> response.respondWithJsonDto(user) }
.onError { error -> ErrorReposne(BAD_REQUEST, error) }
}
class UserFacade {
// You can start adoption in a regular, non-functional codebases
fun createUser(username: String): Result<User, String> {
if (userRepository.findUserByName(username).isPresent()) {
return error("User $username already exists")
}
return ok(userRepository.createUser(username))
}
}
internal class UserFacadeTest : UserSpec {
// JUnit support
@Test
fun `should create user with a valid username` () {
// given: a valid username
val username = 'onlypanda'
// when: user is created with the following name
val user = userFacade.createUser(username)
// then: user has been created
assertOk(username, user.map(User::getUsername))
}
}
Option
Similar usage to Optional<Value>
type provided by Java:
Option<String> withValue = Option.of("Value");
Option<String> empty = Option.empty();
Lazy
Lazy<String> completed = new Lazy<>("Value");
Lazy<String> lazy = new Lazy<>(() -> "Value");
Lazy<Void> initialize = Lazy.ofRunnable(() -> "Called just once);
String value = completed.get();
Completable
Completable<String> completable = Completable.create();
completable
.thenApply(value -> parseBoolean(value))
.then(value -> System.out.println(value));
completable.complete("true");
Reactive
Reference<Integer> a = reference(1);
MutableReference<Integer> b = mutableReference(2);
Computed<Integer> result = computed(dependencies(a, b), () -> a.get() + b.get());
result.subscribe(value -> System.out.println(value));
b.update(3); // prints "4"
Panda Stream
PandaStream<String> empty = PandaStream.empty();
PandaStream<String> standard = PandaStream.of(new ArrayList<>().stream());
Used by
- Panda Organization (Panda, Hub, Light)
- Reposilite
- Libraries like CDN, Dependency-Injector
- FunnyGuilds Organization (FunnyGuilds, FunnyCommands)
- Private projects and API consumers of the given libraries