Хранение ссылки на поток - PullRequest
       9

Хранение ссылки на поток

0 голосов
/ 04 января 2019

У меня есть класс, который управляет 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();
  }
}

Хранение ссылки на Поток - это плохая практика? Хотя это работает, оно определенно не выглядит правильным, и ErrorProne помечает его (следовательно, аннотация @MustBeClosed).

MyStreamManager является пружиной @Bean, но используется только одним потоком (это выполняется в пакете).

Я могу думать о двух разных подходах, которые, вероятно, лучше:

  • создать экземпляр MyStreamManager и обернуть его в try-with-resources, передав close() вызов Stream
  • используйте класс Spliterators для создания Spliterator, который делегирует многим Stream s?

Ответы [ 2 ]

0 голосов
/ 04 января 2019

Не думаю, что тот факт, что вы храните Stream как таковой, делает это неловким, но скорее всего, у вас последовательная связь .

Вы должны позвонить 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), и, как мне кажется, его сложнее использовать неправильно.

(Правда, у вас все еще есть последовательная связь здесь: вы должны помнить, чтобы закрыть поток, возвращаемый в необязательном порядке. Вздох.)

0 голосов
/ 04 января 2019

Смешивание императива (пока цикл, попробуйте окончательно) и декларативный (потоки) код вместе не кажется правильным. Если все эти операции синхронны, я думаю, это можно сделать в одном конвейере (вообще без MyStreamManager).

Я думаю, что вы могли бы подумать о переносе некоторой логики на объект, содержащий метод somethingWhichMightProvideAStream, потому что смешивание императивного шаблона итератора с потоковым API не выглядит идиоматическим. Например, он может вернуть List (или даже лучше Stream!) Streams вместо Optional

Подумайте дважды, действительно ли вам нужно закрыть этот поток. Из документации :

Потоки имеют метод BaseStream.close() и реализуют AutoCloseable, но практически все экземпляры потоков на самом деле не нужно закрывать после использования. Обычно только потоки, источником которых является канал ввода-вывода (например, те, которые возвращены Files.lines(Path, Charset)), требуют закрытия.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...