存储对流的引用

时间:2019-01-04 13:50:33

标签: java java-stream

我有一个管理Stream的类:

class MyStreamManager {
    private Stream<Object> currentStream = null;

    boolean hasMoreData() {
        //code here to assert currentStream is null

        final Optional<Stream<Object>> maybeAStream = somethingWhichMightProvideAStream.getNextStream();

        currentStream = maybeAStream.orElse(null);

        return currentStream != null;
    }

    @MustBeClosed
    Stream<Object> getCurrentStream() { return currentStream; }

    void finish() {
        currentStream.close();
        currentStream = null;
    }
}

使用以下样式:

while (myStreamManager.hasMoreData()) {
  try {
       myStreamManager.getCurrentStream().map(...).filter(...); //etc
  } finally {
       myStreamManager.finish();
  }
}

是否正在存储对Stream的引用,例如这种不良做法?虽然这样做有效,但绝对感觉不对,并且ErrorProne正在对其进行标记(因此带有@MustBeClosed注释)。

MyStreamManager是Spring @Bean,但仅由一个线程使用(该线程正在批量运行)。

我可以想到两种可能更好的不同方法:

  • 实例化MyStreamManager并将其包装在try-with-resources中,将close()调用委派给Stream
  • 使用Spliterators类创建一个Spliterator来委派许多Stream的情况?

2 个答案:

答案 0 :(得分:4)

我认为存储Stream本身并不令人感到尴尬,而是您拥有sequential coupling

必须打电话给hasMoreData;然后getCurrentStream();然后finish()。如果您仅在有限的几个地方使用该类,则可能在所有这些地方都可以正确使用它。但是您在每个地方使用它都是错误使用它的新机会。

我想说的是,您的经理班实际上只是在让自己变得更难。

for (Optional<Stream<Object>> opt = somethingWhichMightProvideAStream.getNextStream();
     opt.isPresent();
     opt = somethingWhichMightProvideAStream.getNextStream()) {
  try (Stream<Object> stream = opt.get()) {  // try-with-resources auto-closes the stream
    stream.map(...).filter(...); //etc
  }
}

或:

Optional<Stream<Object>> opt;
while ((opt = somethingWhichMightProvideAStream.getNextStream()).isPresent()) {
  try (Stream<Object> stream = opt.get()) {
    stream.map(...).filter(...); //etc
  }
}

这两种情况下的循环声明都不是很漂亮。但这要短一些(大约只要您已经拥有while / try / finally循环就可以了),而且我认为更难使用错误。

(诚然,这里仍然有顺序耦合:您必须记住关闭在可选中返回的流。叹气。)

答案 1 :(得分:1)

将命令性的(while循环,最终尝试)和声明性的(流)代码混合在一起似乎并不正确。 如果所有这些选择都是同步的,我猜它可以在一个管道中完成(根本不需要MyStreamManager)。

我认为您可以考虑将一些逻辑转移到包含对象的方法somethingWhichMightProvideAStream上,因为将命令式迭代器模式与流API混合看起来并不习惯。例如,它可以返回List的{​​{1}}(甚至更好的是Stream!)而不是Streams

如果确实需要关闭此流,请三思。来自documentation

  

流具有Optional方法并实现BaseStream.close(),但是实际上几乎所有流实例在使用后都不需要关闭。通常,只有源是IO通道的流(例如AutoCloseable返回的流)才需要关闭。