使用Spliterator 而不是Iterator 可以更好地解决此任务。它简化了逻辑,因为您只需通过委托源的 tryAdvance 方法来实现单个方法 tryAdvance。
它还通过将方法characteristics() 和estimateSize() 委托给源来打开性能改进的机会,因为异常转换功能不会改变它们。您还可以获得不错的并行支持,通过委托源实现trySplit。你只需要像第一个Spliterator一样包装结果:
public class Rethrowing<T,E extends Throwable> implements Spliterator<T> {
public static <E extends Throwable, T> Stream<T> translateExceptions(
Stream<T> source, Class<E> catchType,
Function<? super E, ? extends RuntimeException> translator) {
return StreamSupport.stream(new Rethrowing<>(
source.spliterator(), catchType, translator), source.isParallel());
}
private final Spliterator<T> source;
private final Class<E> catchType;
private final Function<? super E, ? extends RuntimeException> translator;
public Rethrowing(Spliterator<T> sp, Class<E> catchType,
Function<? super E, ? extends RuntimeException> translator) {
this.source = sp;
this.catchType = catchType;
this.translator = translator;
}
@Override public boolean tryAdvance(Consumer<? super T> action) {
try { return source.tryAdvance(action); }
catch(Throwable t) {
if(catchType.isInstance(t))
throw translator.apply(catchType.cast(t));
else throw t;
}
}
@Override public int characteristics() {
return source.characteristics();
}
@Override public long estimateSize() {
return source.estimateSize();
}
@Override public Spliterator<T> trySplit() {
Spliterator<T> split = source.trySplit();
return split==null? null: new Rethrowing<>(split, catchType, translator);
}
}
你可以像这样使用这个实用程序类
class ExceptionA extends IllegalStateException {
public ExceptionA(String s) {
super(s);
}
}
class ExceptionB extends IllegalStateException {
public ExceptionB(Throwable cause) {
super(cause);
}
}
Rethrowing.translateExceptions(
Stream.of("foo", "bar", "baz", "", "extra")
.peek(s -> System.err.println("consuming \""+s+'"'))
.map(s -> { if(s.isEmpty()) throw new ExceptionA("empty"); return s; }),
ExceptionA.class, ExceptionB::new)
.forEach(s -> System.err.println("terminal operation on "+s));
得到
consuming "foo"
terminal operation on foo
consuming "bar"
terminal operation on bar
consuming "baz"
terminal operation on baz
consuming ""
Exception in thread "main" ExceptionB: ExceptionA: empty
…
Caused by: ExceptionA: empty
…
这里ExceptionB::new是翻译函数,相当于exA->new ExceptionB(exA)。