当前位置: 首页 > 面试题库 >

注册流“完成”钩子

冷宏茂
2023-03-14
问题内容

使用Java 8 StreamAPI,我想按照以下方式注册“完成钩子”:

Stream<String> stream = Stream.of("a", "b", "c");

// additional filters / mappings that I don't control
stream.onComplete((Completion c) -> {
    // This is what I'd like to do:
    closeResources();

    // This might also be useful:
    Optional<Throwable> exception = c.exception();
    exception.ifPresent(e -> throw new ExceptionWrapper(e));
});

之所以要这样做,是因为我想将资源包装在Stream供API客户端使用的资源中,并且我希望Stream资源一旦被使用就自动清除。如果可能的话,客户可以致电:

Collected collectedInOneGo =
Utility.something()
       .niceLookingSQLDSL()
       .moreDSLFeatures()
       .stream()
       .filter(a -> true)
       .map(c -> c)
       .collect(collector);

而不是当前需要什么:

try (Stream<X> meh = Utility.something()
                            .niceLookingSQLDSL()
                            .moreDSLFeatures()
                            .stream()) {

    Collected collectedWithUglySyntacticDissonance =
    meh.filter(a -> true)
       .map(c -> c)
       .collect(collector);
}

理想情况下,我想了解java.util.stream.ReferencePipeline的各种方法,例如:

@Override
final void forEachWithCancel(Spliterator<P_OUT> spliterator, Sink<P_OUT> sink) {
    try {

        // Existing loop
        do { } while (!sink.cancellationRequested() && spliterator.tryAdvance(sink));
    }

    // These would be nice:
    catch (Throwable t) {
        completion.onFailure(t);
    }
    finally {
        completion.onSuccess();
    }
}

使用现有的JDK 8 API有没有简便的方法?


问题答案:

除了flatMap基于解决方案(由@Holger提出)以外,任何拦截终端操作的解决方案都将易碎于以下代码:

Stream<String> stream = getAutoCloseableStream();
if(stream.iterator().hasNext()) {
    // do something if stream is non-empty
}

根据规范,此类使用绝对合法。不要忘了,iterator()spliterator()为终端流操作,但其执行后,你仍然需要流源的访问。同样,在任何状态下放弃IteratorSpliterator都是完全有效的,因此您只是不知道是否会进一步使用它。

您可以考虑劝告用户不要使用iterator()spliterator(),但是这段代码呢?

Stream<String> stream = getAutoCloseableStream();
Stream.concat(stream, Stream.of("xyz")).findFirst();

这在内部spliterator().tryAdvance()用于第一个流,然后将其放弃(如果close()显式调用生成的流,则将关闭)。您将需要询问用户也不要使用Stream.concat它。据我在您的图书馆内部所知,您经常使用iterator()/
spliterator(),因此您将需要重新访问所有这些地方以解决可能的问题。而且,当然还有许多其他库也使用iterator()/,spliterator()并且此后可能会短路:所有这些库都将与您的功能不兼容。

为什么flatMap基于解决方案的方法在这里起作用?因为在第一次调用hasNext()or时,tryAdvance()它会将 整个
流内容转储到中间缓冲区中并关闭原始流源。因此,根据流大小,您可能会浪费很多中间内存,甚至会浪费大量内存OutOfMemoryError

您也可以考虑将PhantomReferences
保留在Stream对象上并监视ReferenceQueue。在这种情况下,完成将由垃圾收集器触发(这也有一些缺点)。

总之,我的建议是继续尝试资源。



 类似资料:
  • 处理完提交无效数据的情况,本节我们要完成注册表单的功能,如果提交的数据有效,就把用户存入数据库。我们先尝试保存用户,如果保存成功,用户的数据会自动存入数据库,然后在浏览器中重定向,转向新注册用户的资料页面,页面中还会显示一个欢迎消息,构思图如图 7.19 所示。如果保存用户失败了,就交由上一节实现的功能处理。 图 7.19:注册成功后显示的页面构思图 7.4.1 完整的注册表单 要完成注册表单的功

  • 我目前正在写一个wordpress插件,我遇到了一些问题。我的功能在插件激活时不运行。。。谁能告诉我问题出在哪里? 但不幸的是,安装功能不起作用......但当外部类中的代码安装功能是工作

  • 我们正在尝试让一个iOS的应用程序被批准进入AppStore。我们正在我们的应用程序中利用Spotify API的一部分,因此正在使用Spotify网络授权流。 在Spotify提供的登录页面上,它显示了“注册”链接和登录链接。苹果不喜欢这样,因为它违反了“准则3.1.1 -应用内商业支付购买”,因为我们在我们的应用内推广其他应用。我们发现添加< code>nosignup和< code>noli

  • 我正在使用kafka和elasticsearch设置flink流处理器。我想重播我的数据,但当我将并行度设置为1以上时,它不会完成程序,我认为这是因为Kafka流只看到一条消息,将其标识为流的结尾。 有没有办法告诉flink消费群中的所有线程在一个线程完成后立即结束?

  • DaoCloud 账号的注册 感谢您对 DaoCloud 的关注和支持,本文将带您一步一步地加入到 DaoCloud 的大家庭中。希望您能通过 DaoCloud 快速地学习并灵活地使用 Docker 进行项目代码的开发、测试和部署。 在使用 DaoCloud 提供的优质服务之前,您需要先注册一个属于您或您的团队的 DaoCloud 账号。DaoCloud 十分重视用户体验的简易性和灵活性,所以我们

  • 我正在了解Confluent的模式注册表,以满足所有模式管理需求。 我不太理解他们的版本控制方法...有一个的概念,我将其视为一个名称空间。据我所知,subject在模式注册表中必须是唯一。 然后是模式id,或者只是,它也是唯一的。 最后,还有一个。 以下是文档中的片段: :此主题的架构版本,每个主题从1开始 :全局唯一的架构版本id,在所有主题中的所有架构中都是唯一的 因此,一旦我想修改特定主题