В последнее время я много читал о потоках Java 8, а также несколько статей о отложенной загрузке потоков Java 8: здесь и здесь .Кажется, я не могу поколебать ощущение, что отложенная загрузка ПОЛНОСТЬЮ бесполезна (или, в лучшем случае, незначительное синтаксическое удобство, предлагающее нулевое значение производительности).
Давайте возьмем этот код в качестве примера:
int[] myInts = new int[]{1,2,3,5,8,13,21};
IntStream myIntStream = IntStream.of(myInts);
int[] myChangedArray = myIntStream
.peek(n -> System.out.println("About to square: " + n))
.map(n -> (int)Math.pow(n, 2))
.peek(n -> System.out.println("Done squaring, result: " + n))
.toArray();
Это войдет в консоль, потому что terminal operation
, в данном случае toArray()
, вызывается, и наш поток ленив и выполняется только при вызове операции терминала.Конечно, я также могу сделать это:
IntStream myChangedInts = myIntStream
.peek(n -> System.out.println("About to square: " + n))
.map(n -> (int)Math.pow(n, 2))
.peek(n -> System.out.println("Done squaring, result: " + n));
И ничего не будет напечатано, потому что карта не происходит, потому что мне не нужны данные.Пока я не назову это:
int[] myChangedArray = myChangedInts.toArray();
И вуаля, я получаю свои сопоставленные данные и журналы консоли.За исключением того, что я вижу нулевую пользу для него вообще.Я понимаю, что могу определить код фильтра задолго до того, как я вызову toArray()
, и я могу обойти этот «не очень фильтрованный поток», но что с того? Это единственное преимущество?
Статьи, похоже, подразумевают увеличение производительности, связанное с ленью, например:
В API потоков Java 8 промежуточные операции являются ленивыми, и их модель внутренней обработки оптимизированачтобы он был способен обрабатывать большие объемы данных с высокой производительностью.
и
Java 8 Streams API оптимизирует потоковую обработку с помощью операций короткого замыкания.Методы короткого замыкания заканчивают обработку потока, как только выполняются их условия. В обычных словах операции короткого замыкания, когда условие выполняется, просто нарушают все промежуточные операции, находящиеся ранее в конвейере. Некоторые промежуточные, а также терминальные операцииесть такое поведение.
Звучит буквальноЭто похоже на разрыв цикла и вовсе не связано с ленью.
Наконец, во второй статье есть такая недоумение:
Ленивые операции достигают эффективности.Это способ не работать с устаревшими данными.Ленивые операции могут быть полезны в ситуациях, когда входные данные потребляются постепенно, а не с полным набором элементов заранее.Например, рассмотрим ситуации, когда бесконечный поток был создан с использованием Stream # generate (Supplier ), и предоставленная функция Supplier постепенно получает данные с удаленного сервера.В таких ситуациях серверный вызов будет выполняться только при работе терминала, когда это необходимо.
Не работает с устаревшими данными?Какие?Как отложенная загрузка мешает кому-то работать с устаревшими данными?
TLDR: есть ли польза от отложенной загрузки, кроме возможности запускать операции фильтра / отображения / уменьшения / любой другой операции в более позднее время (чтопредлагает нулевой выигрыш в производительности)?
Если да, то каков реальный вариант использования?