Checked Exception Wrapping Utilities
Wrap checked exceptions for use in lambdas and streams: sneaky throws, functional wrappers, and Either.
import java.util.*;
import java.util.function.*;
import java.util.stream.*;
public class CheckedExceptionUtils {
// Functional interfaces that allow checked exceptions
@FunctionalInterface
public interface CheckedFunction<T, R> {
R apply(T t) throws Exception;
}
@FunctionalInterface
public interface CheckedSupplier<T> {
T get() throws Exception;
}
@FunctionalInterface
public interface CheckedConsumer<T> {
void accept(T t) throws Exception;
}
// Wrap checked → unchecked
public static <T, R> Function<T, R> unchecked(CheckedFunction<T, R> fn) {
return t -> {
try { return fn.apply(t); }
catch (Exception e) { throw new RuntimeException(e); }
};
}
public static <T> Supplier<T> unchecked(CheckedSupplier<T> fn) {
return () -> {
try { return fn.get(); }
catch (Exception e) { throw new RuntimeException(e); }
};
}
public static <T> Consumer<T> unchecked(CheckedConsumer<T> fn) {
return t -> {
try { fn.accept(t); }
catch (Exception e) { throw new RuntimeException(e); }
};
}
// Either type for error-as-value
public sealed interface Either<L, R> {
record Left<L, R>(L value) implements Either<L, R> {}
record Right<L, R>(R value) implements Either<L, R> {}
static <L, R> Either<L, R> left(L value) { return new Left<>(value); }
static <L, R> Either<L, R> right(R value) { return new Right<>(value); }
default <T> T fold(Function<L, T> onLeft, Function<R, T> onRight) {
return switch (this) {
case Left<L, R> l -> onLeft.apply(l.value);
case Right<L, R> r -> onRight.apply(r.value);
};
}
}
// Try with Either (errors as values)
public static <T, R> Function<T, Either<Exception, R>> trying(
CheckedFunction<T, R> fn) {
return t -> {
try { return Either.right(fn.apply(t)); }
catch (Exception e) { return Either.left(e); }
};
}
public static void main(String[] args) {
// Use checked functions in streams
List<String> urls = List.of("file1.txt", "file2.txt", "missing.txt");
// Wrap for stream use
List<String> contents = urls.stream()
.map(unchecked(name -> {
if (name.equals("missing.txt")) throw new java.io.FileNotFoundException(name);
return "content of " + name;
}))
.toList();
// Either approach — collects errors instead of throwing
var results = urls.stream()
.map(trying(name -> {
if (name.equals("missing.txt")) throw new java.io.FileNotFoundException(name);
return "content of " + name;
}))
.toList();
results.forEach(either -> {
String msg = either.fold(
err -> "ERROR: " + err.getMessage(),
ok -> "OK: " + ok
);
System.out.println(msg);
});
}
}Use Cases
- Using checked-exception methods in lambda expressions
- Stream processing with fallible operations
- Functional error handling without try-catch
Tags
Related Snippets
Similar patterns you can reuse in the same workflow.
Functional Interfaces and Lambda Patterns
Use built-in and custom functional interfaces: Predicate, Function, Consumer, Supplier, and composition.
Best for: Composable validation and filtering logic
Method References — All Four Types
Use method references for concise lambda expressions: static, instance, arbitrary object, and constructor.
Best for: Concise functional-style code with method references
Java Streams — Filter, Map, Collect
Process collections with Java Streams: filter, map, flatMap, reduce, and collect to lists or maps.
Best for: Transforming and filtering collections
Strategy Pattern with Lambdas
Implement the Strategy pattern using interfaces and Java lambdas for flexible algorithm selection.
Best for: Swappable pricing or discount algorithms