94. Checked Exceptions in Streams and Lambdas
Functional interfaces in java.util.function do not declare checked exceptions, so lambdas that throw checked exceptions don't compile; the fix is a wrapper method, a sneaky-throw helper, or switching to unchecked exceptions.
Explanation
Function<T,R> declares R apply(T t) with no throws clause. If your lambda body throws a checked exception (IOException, SQLException, etc.), the compiler rejects it โ you're trying to throw a checked exception from a context that doesn't declare it.
Option 1 โ Wrapper method: write a private method that catches the checked exception and rethrows as unchecked. Clean, explicit, testable.
Option 2 โ Sneaky throw helper: use a utility that exploits generic type erasure to throw a checked exception without declaring it (used by Lombok's @SneakyThrows). Convenient but hides exception information from callers โ use carefully.
Option 3 โ Custom checked functional interface: define your own @FunctionalInterface ThrowingFunction<T,R> { R apply(T t) throws Exception; } and write an adapter that wraps it. Good for internal APIs.
Example
import java.io.*;
import java.util.List;
import java.util.stream.Collectors;
public class CheckedExceptionStreams {
static String readFile(String path) throws IOException {
return new String(new FileInputStream(path).readAllBytes());
}
// Option 1: wrapper method (safest)
static String readFileUnchecked(String path) {
try {
return readFile(path);
} catch (IOException e) {
throw new RuntimeException("Failed to read: " + path, e);
}
}
// Option 2: sneaky-throw helper (use sparingly)
@SuppressWarnings("unchecked")
static <E extends Throwable, T> T sneakyThrow(Throwable t) throws E {
throw (E) t;
}
// Option 3: custom checked functional interface
@FunctionalInterface
interface ThrowingFunction<T, R> {
R apply(T t) throws Exception;
}
static <T, R> java.util.function.Function<T, R> wrap(ThrowingFunction<T, R> fn) {
return t -> {
try { return fn.apply(t); }
catch (Exception e) { throw new RuntimeException(e); }
};
}
public static void main(String[] args) {
List<String> paths = List.of("/tmp/a.txt", "/tmp/b.txt");
// BAD: doesn't compile!
// paths.stream().map(p -> readFile(p)).toList(); // error
// Option 1: wrapper
List<String> contents1 = paths.stream()
.map(CheckedExceptionStreams::readFileUnchecked)
.collect(Collectors.toList());
System.out.println("Option 1 done (files may not exist โ RuntimeException expected)");
// Option 3: wrap() adapter
List<String> contents3 = paths.stream()
.map(wrap(CheckedExceptionStreams::readFile))
.collect(Collectors.toList());
}
}Sources
- https://docs.oracle.com/en/java/javase/21/docs/api/java.base/java/util/function/Function.html โ Function API
- https://docs.oracle.com/javase/specs/jls/se21/html/jls-11.html#jls-11.2 โ JLS: checked exception compile rules