Java8流-增量收集/部分减少/间歇映射/…这到底叫什么?

Java8流-增量收集/部分减少/间歇映射/…这到底叫什么?,java,dictionary,java-8,java-stream,reduce,Java,Dictionary,Java 8,Java Stream,Reduce,我正在处理一个可能无限的数据元素流,这些数据元素遵循以下模式: E1 E2富 E3巴 ... En-1巴 EN 也就是说,一个s流,在我可以将它们映射到对象模型之前,必须将其累积在缓冲区中 目标:将流聚合为流,而无需在无限流上进行收集 在英语中,代码类似于“一旦看到开始标记,就开始缓冲。缓冲,直到看到结束标记,然后准备返回旧缓冲,并准备一个新缓冲。返回旧缓冲。” 我当前的实现形式如下: Data<String>.stream() .map(function

我正在处理一个可能无限的数据元素流,这些数据元素遵循以下模式:


E1
E2富
E3巴
...
En-1巴
EN

也就是说,一个s流,在我可以将它们映射到对象模型之前,必须将其累积在缓冲区中

目标:将
聚合为
,而无需在无限流上进行收集

在英语中,代码类似于“一旦看到开始标记,就开始缓冲。缓冲,直到看到结束标记,然后准备返回旧缓冲,并准备一个新缓冲。返回旧缓冲。”

我当前的实现形式如下:

Data<String>.stream()
            .map(functionReturningAnOptionalPresentOnlyIfObjectIsComplete)
            .filter(Optional::isPresent)
Data.stream()
.map(函数返回NoOptionalPresentonlyFobjectisComplete)
.filter(可选::isPresent)
我有几个问题:

  • 这个操作的正确名称是什么?(也就是说,我可以在谷歌上搜索更多的例子吗?我找到的每一个关于
    .map()
    的讨论都是关于1:1映射的。每一个关于.reduce的讨论)都是关于n:1还原的。关于
    .collect()
    的每一次讨论都谈到了作为终端操作的累积…)

  • 这在很多方面都很糟糕。有没有更好的方法来实现这一点?(表格
    .collectunlconditiontheapplyfinisher(收集器、条件、完成器)
    ..的候选者)


  • 谢谢

    为了避免混乱,可以在映射之前进行筛选

    Data<String>.stream()
        .filter(text -> canBeConvertedToObject(text))
        .map(text -> convertToObject(text))
    
    Data.stream()
    .filter(文本->canBeConvertedToObject(文本))
    .map(文本->转换对象(文本))
    

    它在无限流上工作得非常好,只构造需要构造的对象。它还避免了创建不必要的可选对象的开销。

    不幸的是,Java8流API中没有部分reduce操作。然而,这样的操作是在我的库中实现的,它增强了标准的Java8流。所以你的任务可以这样解决:

    Stream<ObjectDefinedByStrings> result = 
        StreamEx.of(strings)
                .groupRuns((a, b) -> !b.contains("<start mark>"))
                .map(stringList -> constructObjectDefinedByStrings());
    

    我为这个部分缩减提出了另外两个用例:

    1.解析SQL和PL/SQL(Oracle过程)语句 SQL语句的标准分隔符是分号(
    )。它将普通SQL语句彼此分离。但若您有PL/SQL语句,那个么分号将语句中的运算符彼此分开,而不仅仅是整个语句

    解析同时包含普通SQL和PL/SQL语句的脚本文件的方法之一是首先用分号将它们拆分,然后如果特定语句以特定关键字开头(
    DECLARE
    BEGIN
    ,等等),则按照PL/SQL语法规则将此语句与下一个语句连接起来

    顺便说一下,这不能通过使用
    StreamEx
    partial reduce操作来实现,因为它们只测试两个相邻的元素。因为您需要了解从初始PL/SQL关键字元素开始的以前的流元素,以确定是将当前元素包括到部分缩减中还是应该完成部分缩减。在这种情况下,可变部分还原可以在收集器保存已收集元素的信息和一些
    谓词
    仅测试收集器本身(如果应完成部分还原)或
    BiPredicate
    同时测试收集器和当前流元素的情况下使用

    理论上,我们谈论的是使用流管道思想实现LR(0)或LR(1)解析器(请参阅)。LR解析器可用于解析大多数编程语言的语法

    解析器是一个具有堆栈的有限自动机。对于LR(0)自动机,其转换仅取决于堆栈。在LR(1)自动机的情况下,它取决于堆栈和流中的下一个元素(理论上可以有LR(2)、LR(3)等自动机查看2、3等。确定转换的下一个元素,但实际上所有编程语言在语法上都是LR(1)语言)

    要实现解析器,应该有一个
    收集器
    ,其中包含有限自动机堆栈,并对是否达到该自动机的最终状态进行谓词测试(这样我们就可以停止缩减)。对于LR(0),它应该是
    谓词
    测试
    收集器
    本身。对于LR(1),它应该是
    BiPredicate
    测试
    收集器和流中的下一个元素(因为转换取决于堆栈和下一个符号)

    因此,要实现LR(0)解析器,我们需要如下类似的东西(
    T
    是流元素类型,
    A
    是同时包含有限自动机堆栈和结果的累加器,
    R
    是每个解析器工作形成输出流的结果):

    注意:在这种情况下,
    BiPredicate
    应先测试元素,然后它将被累加器消耗。请记住,LR(1)解析器正在窥视下一个元素以确定转换。因此,如果空累加器拒绝接受下一个元素(供应商和下一个流元素刚刚创建的空累加器上,
    BiPredicate
    返回true,表示部分减少结束),则可能存在潜在的异常

    2.基于流元素类型的条件批处理 在执行SQL语句时,我们希望将相邻的数据修改(DML)语句合并到单个批处理中(请参阅JDBCAPI),以提高总体性能。但我们不想批量查询。所以我们需要条件批处理(而不是像中那样的无条件批处理)

    对于这种特定情况,可以使用
    StreamEx
    部分reduce操作,因为如果由
    BiPredicate
    测试的两个相邻元素都是DML语句,则应将它们包含在批处理中。所以我们不需要知道以前的批量收集历史

    但我们可以增加任务的复杂性,并说批次应该受到大小的限制。比如说,不超过100个DML语句i
    Stream<ObjectDefinedByStrings> result = 
        StreamEx.of(strings)
                .collapse((a, b) -> !b.contains("<start mark>"), Collectors.joining())
                .map(joinedString -> constructObjectDefinedByStrings());
    
    <R,A> Stream<R> Stream<T>.parse(
        Collector<T,A,R> automataCollector,
        Predicate<A> isFinalState)
    
    <R,A> Stream<R> Stream<T>.parse(
        BiPredicate<A, T> isFinalState
        Collector<T,A,R> automataCollector)