【问题标题】:Java 8 read from an input stream to an output stream, while aggregating itemsJava 8 从输入流读取到输出流,同时聚合项目
【发布时间】:2015-11-15 05:47:03
【问题描述】:

实际任务是能够通过从文件中读取来返回 Stream,但这样做不会将整个文件(或解析的集合)完全加载到内存中。该流的目的可能会在以后确定——例如保存到数据库。开发人员将拥有一个反序列化流(而不是反序列化集合)的句柄。

问题在于不能保证文件中的一行等于一个 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 获得的流是无限的。没有停止条件。抛出异常有效(有点)。或者选择完全不同的(经典)方法。

【问题讨论】:

    标签: java stream java-8 java-stream


    【解决方案1】:

    考虑实现您的自定义Spliterator,而不是Supplier。它不像最初看起来那样令人生畏(通过检查Spliterator 接口),因为有Spliterators.AbstractSpliterator 基类使它变得非常容易:只需提供tryAdvance(),它看起来与您现在所拥有的基本相同在Supplier

    停止条件变得简单:让tryAdvance()返回false

    【讨论】:

    • 然后使用StreamSupport.stream返回它。谢谢,我试试看。我想知道流是否会保持懒惰。我会做一些测试并回帖。
    • 当然会——所有流都由 Spliterator 支持,您将获得与您的完全相同的行为。如果您对并行化感兴趣,也可以查看my other post
    【解决方案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&lt;List&lt;String&gt;&gt; 哪些元素是分组字符串的列表,因此您可以处理它们以创建您的 MyEntity 对象。如果您不喜欢中间的List,您可以编写Collector 来创建您的MyEntity,并使用collapse(BiPredicate, Collector) 方法接受相同的BiPredicate 和任何Collector 来执行部分减少。

    【讨论】:

      猜你喜欢
      • 2011-05-29
      • 2012-02-26
      • 1970-01-01
      • 2014-12-04
      • 2018-05-25
      • 1970-01-01
      • 1970-01-01
      • 2015-05-30
      • 1970-01-01
      相关资源
      最近更新 更多