Java 8 Stream API 方法(如 map
、filter
和 forEach
)不允许直接检查异常。
在 Java Stream API 中处理异常可能很棘手,因为 map
、filter
和 forEach
等典型方法需要不允许检查异常的函数接口。我们不能处理这些,至少不能直接处理。
例如,下面的代码将导致我们的 Stream 管道中出现异常:
List<Integer> numbers = Arrays.asList(10, 5, 0, 3);
// This will throw ArithmeticException when number is 0
numbers.stream()
.map(number -> divide(100, number))
.forEach(result -> System.out.println("Result: " + result));
这些是处理 Checked Exceptions (受检异常)的非常标准的方法,所以让我们看看实现这一点的方法:
将选中的异常包装在 Unchecked Exceptions (非受检异常)中
public class StreamExceptionHandling {
public static void main(String[] args) {
List<String> data = Arrays.asList("1", "2", "three", "4");
List<Integer> result = data.stream()
.map(s -> wrap(() -> Integer.parseInt(s)))
.collect(Collectors.toList());
System.out.println(result);
}
@FunctionalInterface
public interface CheckedFunction<T, R> {
R apply(T t) throws Exception;
}
public static <T, R> java.util.function.Function<T, R> wrap(CheckedFunction<T, R> function) {
return t -> {
try {
return function.apply(t);
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
}
处理 Lambda 中的异常
直接在 lambda 表达式中捕获异常,但这可能会使代码不那么干净。
List<String> data = Arrays.asList("1", "2", "three", "4");
List<Integer> result = data.stream()
.map(s -> {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
System.err.println("Failed to parse: " + s);
return null;
}
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
System.out.println(result);
对函数使用自定义包装器
创建一个自定义包装器,用于处理异常并返回特殊结果或重新引发异常。
List<String> data = Arrays.asList("1", "2", "three", "4");
List<Optional<Integer>> result = data.stream()
.map(s -> handleException(() -> Integer.parseInt(s)))
.collect(Collectors.toList());
result.forEach(System.out::println);
public static <T> Optional<T> handleException(Supplier<T> supplier) {
try {
return Optional.ofNullable(supplier.get());
} catch (Exception e) {
return Optional.empty();
}
}
使用自定义功能接口
创建允许引发异常并相应地处理异常的自定义函数接口。
@FunctionalInterface
public interface ThrowingFunction<T, R> {
R apply(T t) throws Exception;
}
public static <T, R> Function<T, R> throwingFunctionWrapper(ThrowingFunction<T, R> function) {
return i -> {
try {
return function.apply(i);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
};
}
List<String> data = Arrays.asList("1", "2", "three", "4");
List<Integer> result = data.stream()
.map(throwingFunctionWrapper(Integer::parseInt))
.collect(Collectors.toList());
System.out.println(result);
## 使用 Try
Wrapper(来自 Vavr 等库)
如果您愿意使用外部库,Vavr 提供了一个 Try
monad,它允许以更实用的方式处理异常。
import io.vavr.control.Try;
List<String> data = Arrays.asList("1", "2", "three", "4");
List<Integer> result = data.stream()
.map(s -> Try.of(() -> Integer.parseInt(s)).getOrElse(-1))
.collect(Collectors.toList());
System.out.println(result);
感谢阅读,希望本文对您有用!
没有回复内容