你可以通过包装你的lambda来抛出一个未检查的异常,然后在终端操作中解开这个未检查的异常,从而滚动你自己的Stream变体:
@FunctionalInterface
public interface ThrowingPredicate<T, X extends Throwable> {
public boolean test(T t) throws X;
}
@FunctionalInterface
public interface ThrowingFunction<T, R, X extends Throwable> {
public R apply(T t) throws X;
}
@FunctionalInterface
public interface ThrowingSupplier<R, X extends Throwable> {
public R get() throws X;
}
public interface ThrowingStream<T, X extends Throwable> {
public ThrowingStream<T, X> filter(
ThrowingPredicate<? super T, ? extends X> predicate);
public <R> ThrowingStream<T, R> map(
ThrowingFunction<? super T, ? extends R, ? extends X> mapper);
public <A, R> R collect(Collector<? super T, A, R> collector) throws X;
// etc
}
class StreamAdapter<T, X extends Throwable> implements ThrowingStream<T, X> {
private static class AdapterException extends RuntimeException {
public AdapterException(Throwable cause) {
super(cause);
}
}
private final Stream<T> delegate;
private final Class<X> x;
StreamAdapter(Stream<T> delegate, Class<X> x) {
this.delegate = delegate;
this.x = x;
}
private <R> R maskException(ThrowingSupplier<R, X> method) {
try {
return method.get();
} catch (Throwable t) {
if (x.isInstance(t)) {
throw new AdapterException(t);
} else {
throw t;
}
}
}
@Override
public ThrowingStream<T, X> filter(ThrowingPredicate<T, X> predicate) {
return new StreamAdapter<>(
delegate.filter(t -> maskException(() -> predicate.test(t))), x);
}
@Override
public <R> ThrowingStream<R, X> map(ThrowingFunction<T, R, X> mapper) {
return new StreamAdapter<>(
delegate.map(t -> maskException(() -> mapper.apply(t))), x);
}
private <R> R unmaskException(Supplier<R> method) throws X {
try {
return method.get();
} catch (AdapterException e) {
throw x.cast(e.getCause());
}
}
@Override
public <A, R> R collect(Collector<T, A, R> collector) throws X {
return unmaskException(() -> delegate.collect(collector));
}
}
然后你可以像使用流一样使用它:
Stream<Account> s = accounts.values().stream();
ThrowingStream<Account, IOException> ts = new StreamAdapter<>(s, IOException.class);
return ts.filter(Account::isActive).map(Account::getNumber).collect(toSet());
这个解决方案需要相当多的样板文件,所以我建议您看一看我已经创建的库,它完全符合我在这里为整个Stream类(以及更多!)所描述的内容。