Imagine I\'m building a library, that will receive a Stream of Integers, and all the library code needs to do is return a stream of Strings with the string representation of
The error occurs in the stream intermediate operation, a clever way like as you to solving the problem is using the Proxy Design Pattern. for using the stream api you just need to proxying an Iterator
from the source Stream
to another Stream
by StreamSupport#stream & Spliterators#spliterator(Iterator, long, int) , for example:
Stream result = convertToString(Stream.of("1", "bad", "2")
.map(Integer::parseInt));
public Stream convertToString(Stream input) {
return exceptionally(input, (e, action) -> action.accept(null))
.map(it -> String.format("%s", it == null ? "NaN" : it));
}
Current version Stream is base on Iterator
that fixed the Stream.of(T)
bug, for more details please see my question.
Stream exceptionally(Stream source,
BiConsumer> handler) {
Spliterator s = source.spliterator();
return StreamSupport.stream(
spliterator(
exceptionally(s, handler),
s.estimateSize(),
s.characteristics()
),
source.isParallel()
).onClose(source::close);
}
//Don't worried the thread-safe & robust since it is invisible for anyone
private Iterator exceptionally(Spliterator spliterator,
BiConsumer> handler) {
class ExceptionallyIterator implements Iterator, Consumer {
private Iterator source = Spliterators.iterator(spliterator);
private T value;
private boolean valueInReady = false;
private boolean stop = false;
@Override
public boolean hasNext() {
while (true) {
if (valueInReady) return true;
if (stop) return false;
try {
return source.hasNext();
} catch (Exception ex) {
stop = shouldStopTraversing(ex);
handler.accept(ex, this);
}
}
}
@Override
public T next() {
return valueInReady ? dump() : source.next();
}
private T dump() {
T result = value;
valueInReady = false;
value = null;
return result;
}
@Override
public void accept(T value) {
this.value = value;
this.valueInReady = true;
}
}
return new ExceptionallyIterator();
}
static final String BUG_CLASS = "java.util.stream.Streams$StreamBuilderImpl";
public static boolean shouldStopTraversing(Exception ex) {
for (StackTraceElement element : ex.getStackTrace()) {
if (BUG_CLASS.equals(element.getClassName())) {
return true;
}
}
return false;
}