实际任务是能够通过读取文件来返回Stream,但这样做却不会将整个文件(或已解析的集合)完全加载到内存中。该流的目的可以在以后确定 - 例如保存到DB。开发人员可以使用反序列化的流(而不是反序列化的集合)。
问题在于,无法保证文件中的一行等于一个MyEntity对象(在这种情况下我可以使用本文:http://blog.codeleak.pl/2014/05/parsing-file-with-stream-api-in-java-8.html)
通常,人们可能会发现这样一种情况:如果输入流,则需要返回通过将可变数量的输入流项映射到一个输出流项而构造的输出流。
所以,到目前为止,我的解决方案是使用供应商,如下所示:
public class Parser{
public Stream<MyEntity> parse(final InputStream stream) {
return Stream.generate(new AggregatingSupplier(stream));
}
private class AggregatingSupplier implements Supplier<MyEntity> {
private final Scanner r;
public AggregatingSupplier(final InputStream source) {
this.r= new Scanner(source);
}
@Override
public MyEntity get() {
MyEntity re=new MyEntity();
while (r.hasNextLine() &&!re.isComplete()){
String line=r.nextLine();
// ... do some processing
}
return re;
}
}
}
这种方法的问题在于使用Stream.generate获得的流是无限的。没有停止条件。抛出一个异常(有点)。或者选择完全不同的(经典)方法。
答案 0 :(得分:5)
而不是Supplier
考虑实施自定义Spliterator
。它不像它最初看起来那么令人生畏(通过检查Spliterator
接口),因为有Spliterators.AbstractSpliterator
基类使得它非常简单:只需提供tryAdvance()
,看起来与Supplier
中的内容基本相同。
暂停条件变得简单:只需让tryAdvance()
返回false
。
答案 1 :(得分:2)
使用我的StreamEx库可能会稍微简单一点,因为它具有杀手功能,可根据指定的条件部分减少组合多个相邻元素的流。例如,您可以执行以下操作:
public Stream<MyEntity> parse(final InputStream stream) throws IOException {
return StreamEx.ofLines(new InputStreamReader(stream))
.groupRuns((a, b) -> !isEndOfEntry(a))
.map(strings -> createMyEntityFromListOfStrings(strings));
}
groupRuns
方法接受应用于该对相邻行的BiPredicate
,如果这些行属于同一组,则应返回true。如果您有标记条目最后一行的特定标记,则可以测试第一个字符串(a
)。或者,如果更容易检测新条目的开头,则可以检查字符串b
。此方法创建StreamEx<List<String>>
哪些元素是分组字符串列表,因此您可以处理它们以创建MyEntity
对象。如果您不想拥有中级List
,则可以编写Collector
来创建MyEntity
并使用接受相同BiPredicate
的{{3}}方法和任何Collector
执行部分缩减。