Let's say I have the following method I want to refactor
protected Stream<T> parseFile(File file, Consumer<File> cleanup) {
try {
return parser.parse(file); // returns a Stream<T>
} catch (XmlParseException e) { // child of RuntimeException
throw new CustomRuntimeException(e);
} finally {
if (file != null) {
cleanup.accept(file);
}
}
throw new IllegalStateException("Should not happen");
}
This method's purpose is to act as a proxy attaching error handling on the stream rethrowing in a wrapping exception CustomRuntimeException
. So when we consume it later in the flow, I don't have to handle those exceptions everywhere but only CustomRuntimeException
.
Upstream, I used that method as follow
try {
Stream<T> stream = parseFile(someFile);
stream.map(t -> ...);
catch (CustomRuntimeException e) {
// do some stuff
}
And here's what the parser.parse method looks like
public Stream<T> parse() {
// ValueIterator<T> implements Iterator<T>, AutoCloseable
XmlRootParser.ValueIterator<T> valueIterator = new XmlRootParser.ValueIterator(this.nodeConverter, this.reader, this.nodeLocalName, this.nodeName);
Stream<T> stream = StreamSupport.stream(Spliterators.spliteratorUnknownSize(valueIterator, 1040), false);
stream.onClose(valueIterator::close);
return stream;
}
The exceptions I want to handle will be thrown by the ValueIterator.hasNext method. Which means they won't be thrown at Stream creation but only at Stream consumption (calling foreach/map/count/collect/... on the stream).
How do I attach error handling on my stream in method parseFile
nicely without having to consume the stream? Is it possible?
Obviously this code will work only if the parser.parse
method consume its stream before returning it. Which is against using streams.