【发布时间】:2018-02-08 03:08:08
【问题描述】:
假设我有以下方法要重构
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");
}
此方法的目的是充当代理,在包装异常CustomRuntimeException 中重新抛出流上的错误处理。因此,当我们稍后在流程中使用它时,我不必处处处理这些异常,而只需处理 CustomRuntimeException。
上游,我使用的方法如下
try {
Stream<T> stream = parseFile(someFile);
stream.map(t -> ...);
catch (CustomRuntimeException e) {
// do some stuff
}
这就是 parser.parse 方法的样子
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;
}
我要处理的异常将由 ValueIterator.hasNext 方法抛出。这意味着它们不会在 Stream 创建时被抛出,而只会在 Stream 消费时抛出(在流上调用 foreach/map/count/collect/...)。
如何在parseFile 方法中很好地在我的流上附加错误处理,而不必使用流?有可能吗?
显然,此代码仅在 parser.parse 方法在返回之前消耗其流时才有效。这是反对使用流的。
【问题讨论】:
-
@RomanC 有什么联系?
-
zipWithIndex 方法@RomanC 对吗?
-
我认为不进入
parser.parse()是不可能的。 -
当迭代器的
hasNext()方法抛出异常时,唯一遇到的地方就是终端操作。在您的问题示例中,甚至没有终端操作。对于指定的目的,所有这些catch块都是无用的。那么,您想要的只是捕获并转换hasNext()方法抛出的异常? -
剩下的一些问题:
T是什么?throw new IllegalStateException("Should not happen");声明的意义何在,即使编译器也会拒绝任何声明为不可访问?为什么调用者应该提供Consumer<File> cleanup参数,而调用者知道何时执行清理,即当流已被消耗时?您是否知道示例调用者缺少关闭流(try(…) {}语句)?如何将File传递给不声明任何参数的parse方法?
标签: java java-8 java-stream