Как реализовать поток Java?
Я хочу реализовать Stream<T>
.
Я не хочу просто использовать implements Stream<T>
, потому что мне пришлось бы реализовать тонну методов.
Можно ли этого избежать?
Чтобы быть более конкретным, как я могу передать t1
, t2
и t3
, например:
class Foo<T> {
T t1, t2, t3;
Foo(T t1, T t2, T t3) {
this.t1 = t1;
this.t2 = t2;
this.t3 = t3;
}
}
Ответы
Ответ 1
Стандартная реализация JQK Stream
- это внутренний класс java.util.stream.ReferencePipeline
, вы не можете его напрямую создать.
Вместо этого вы можете использовать java.util.stream.Stream.builder()
, java.util.stream.StreamSupport.stream(Spliterator <T>, boolean)
и различные 2 другие статические методы factory для создания экземпляра реализации по умолчанию.
Использование spliterator, вероятно, является самым мощным подходом, поскольку он позволяет вам ленизировать объекты, а также обеспечивает эффективную распараллеливание, если ваш источник можно разделить на несколько кусков.
Кроме того, вы также можете конвертировать потоки обратно в разделители, обернуть их в пользовательский разделитель и затем преобразовать их обратно в поток, если вам нужно реализовать свои собственные промежуточные операции с промежуточным состоянием - например. из-за недостатков в стандартных API-интерфейсах - поскольку большинство доступных промежуточных операций не разрешено сохранять состояние. См. этот ответ SO для пример.
В принципе вы могли бы написать свою собственную реализацию интерфейса потока, но это было бы довольно утомительно.
Ответ 2
Обычно вам не нужно писать собственный класс потока. Вместо этого вы можете создавать поток существующими методами. Например, вот как создать поток значения 1, 100:
AtomicInteger n = new AtomicInteger(0);
Stream<Integer> stream = Stream.generate(() -> n.incrementAndGet()).limit(100);
поэтому здесь мы создали бесконечный поток целых чисел: 1, 2, 3,.... тогда мы использовали limit(100)
для этого бесконечного потока, чтобы вернуть поток из 100 элементов.
Для ясности, если вы хотите поток целых чисел (с фиксированными интервалами), вы должны использовать IntStream.range()
. Это просто пример, показывающий, как потоки могут быть определены с помощью Stream.generate()
, что дает вам большую гибкость, поскольку позволяет использовать произвольную логику для определения элементов пара.
Ответ 3
Если вы хотите создать свой собственный поток, потому что вам нужна пользовательская логика close()
, самым простым решением является создание потока из итератора и вызов onClose(Runnable)
. Например, для потока из Reader через Джексон:
MappingIterator<?> values = objectMapper.reader(type).readValues(reader);
return StreamSupport
.stream(Spliterators.spliteratorUnknownSize(values, Spliterator.ORDERED), false)
.onClose(() -> {
try {
reader.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
});
Ответ 4
Другие ответили, как обеспечить реализацию универсального Stream
. Что касается вашего конкретного требования, просто выполните следующее:
class Foo<T> {
T t1, t2, t3;
Foo(T t1, T t2, T t3) {
this.t1 = t1;
this.t2 = t2;
this.t3 = t3;
}
Stream<T> stream() {
return Stream.of(t1, t2, t3);
}
}
Ответ 5
Для полноты, поскольку я не нашел это прямо среди ответов здесь на SO:
Если вы хотите преобразовать существующий Iterator в поток (например, потому что вы хотите генерировать элементы последовательно), используйте это:
StreamSupport.stream(
Spliterators.spliterator(myIterator, /* initial size*/ 0L, Spliterator.NONNULL),
/* not parallel */ false);
Я нашел это немного сложно найти, так как вам нужно знать StreamSupport, Spliterators и Spliterator