Checked Functions
Functional interfaces that may throw checked exceptions, returning Result on the way out.
Java’s built-in Function, BiFunction, Consumer and friends cannot throw checked exceptions without wrapping. functional-reactive ships drop-in replacements that can throw, and return a Result<T> so failures travel through your pipeline without explicit try/catch.
The family
All live under com.svenruppert.functional.functions.
| Interface | Extends | Throwing method | Safe method (returns) |
|---|---|---|---|
CheckedFunction<T, R> | Function<T, Result<R>> | R applyWithException(T) throws Exception | Result<R> apply(T) |
CheckedBiFunction<T1, T2, R> | BiFunction<T1, T2, Result<R>> | R applyWithException(T1, T2) throws Exception | Result<R> apply(T1, T2) |
CheckedTriFunction<T1, T2, T3, R> | โ | R applyWithException(T1, T2, T3) throws Exception | Result<R> apply(T1, T2, T3) |
CheckedSupplier<T> | Supplier<Result<T>> | T getWithException() throws Exception | Result<T> get() |
CheckedConsumer<T> | CheckedFunction<T, Void> | inherited | inherited |
CheckedExecutor | โ | void applyWithException() throws Exception | Result<Void> execute() |
CheckedPredicate<T> | โ | boolean testWithExceptions(T) throws Exception | boolean test(T) (returns false on throw) |
The key design choice: every Checked* interface either extends the matching JDK interface (so it slots into existing APIs) or carries enough surface to be useful on its own. The throwing method is what you implement; the framework wraps it in a try/catch and produces a Result (or false, for predicates).
Lifting a throwing method reference
The most common usage is a cast from a method reference:
import com.svenruppert.functional.functions.CheckedFunction;
import com.svenruppert.functional.model.Result;
Result<Integer> r1 = ((CheckedFunction<String, Integer>) Integer::parseInt).apply("42");
// Success(42)
Result<Integer> r2 = ((CheckedFunction<String, Integer>) Integer::parseInt).apply("oops");
// Failure("For input string: \"oops\"")
Because CheckedFunction<T, R> extends Function<T, Result<R>>, you can also assign it to a plain Function for cleaner call sites:
Function<String, Result<Integer>> parseInt = (CheckedFunction<String, Integer>) Integer::parseInt;
Stream.of("1", "2", "Hi", "3")
.map(parseInt) // Stream<Result<Integer>>
.flatMap(Result::stream) // Stream<Integer> โ failed parses drop out
.reduce(Integer::sum)
.ifPresent(System.out::println); // 6
A small helper: tryIt
When you want even less ceremony at the call site, wrap the cast in a tiny helper:
public static <T, R> Function<T, Result<R>> tryIt(CheckedFunction<T, R> function) {
Objects.requireNonNull(function);
return function;
}
Function<String, Result<Integer>> parse = tryIt(Integer::parseInt);
parse.apply("42").ifPresent(System.out::println); // 42
Or as a function value if you want to compose it:
public static <T, R> Function<CheckedFunction<T, R>, Function<T, Result<R>>> tryIt = f -> f;
Function<String, Result<Integer>> parse = tryIt.apply(Integer::parseInt);
Pick whichever style your codebase prefers.
Sequencing multiple throwing calls
The classic problem: several methods in a row each declare throws Exception, and you want all of them to run even if an earlier one fails (think test teardown):
Function<String, Result<String>> stepA = (CheckedFunction<String, String>) (txt) -> serviceA.doWork(txt);
Function<String, Result<String>> stepB = (CheckedFunction<String, String>) (txt) -> serviceB.doWork(txt);
Result<String> a = stepA.apply(null); // Failure(โฆ)
Result<String> b = stepB.apply("Hello"); // Success("HELLO")
No nested try/catch, both calls execute, and each result carries its reason.
When not to use Checked*
Result.failure carries the exception’s message (or class name if the message is null), not the Throwable itself. If you need stack traces, log at the point of conversion:
CheckedFunction<String, Config> readConfig = path -> {
try {
return new Config(Files.readAllBytes(Paths.get(path)));
} catch (IOException e) {
log.error("config load failed for {}", path, e);
throw e; // still becomes Result.failure with e.getMessage()
}
};
Related
Result<T>โ the failure container everyChecked*produces.- Transformations โ
curryCheckedBiFunction,unCurryCheckedTriFunction,asCheckedFunc(Function). - Tutorial: Working with checked exceptions.