Hi David,
This is a really complex topic, and there are interactions between
things like Errors/RuntimeExceptions and Throwables, together with
sequential evaluation, parallel evaluation, partial evaluation etc.
That being said, Gatherers are extremely versatile, and you could
experiment with encodings that would allow you to add the kind of
information you need.
The following is just an example I threw together to illustrate what I mean:
jshell> public static <T, R> Gatherer<T, ?, R> wrap(Function<? super T,
? extends Stream<? extends R>> f, BiFunction<? super T, ? super
RuntimeException, ? extends RuntimeException> wrapper) {
...> return Gatherer.<T, Void, R>of( // flatMap-semantics
...> Gatherer.defaultInitializer(),
...> (_, element, downstream) -> {
...> try(Stream<? extends R> s = f.apply(element)) {
...> return s != null ?
s.sequential().allMatch(downstream::push) : true; // Not ideal
performance-wise, yet semantically works
...> } catch (RuntimeException re) {
...> throw wrapper.apply(element, re);
...> }
...> },
...> (Void x, Void y) -> x, // "custom" combiner so this
operation can be parallelized
...> Gatherer.defaultFinisher()
...> );
...> }
| created method wrap(Function<? super T, ? extends Stream<? extends
R>>, BiFunction<? super T, ? super RuntimeException, ? extends
RuntimeException>)
jshell> Stream.of(1,2, 0, 3).gather(wrap(i -> Stream.of(i).map(x -> 10 /
x), (i, e) -> new IllegalStateException("Error when processing: " + i,
e))).toList();
| Exception java.lang.IllegalStateException: Error when processing: 0
| ... // trace here
| Caused by: java.lang.ArithmeticException: / by zero
| ... // trace here
On 2026-06-02 02:17, David Alayachew wrote:
Whoops, let me improve that method signature.
public <X1 extends Throwable, X2 extends Throwable> Stream<T>
wrapException(Class<X1> excClass, Function<X1, X2> excTransformer)
--
Cheers,
√
Viktor Klang
Software Architect, Java Platform Group
Oracle