Вы используете неправильный инструмент для своей работы. Как уже было заметно в вашем примере кода, Supplier
, переданный Stream.generate
, должен идти на все, чтобы поддерживать индекс, необходимый для извлечения страниц.
Что еще хуже, так это то, что Stream.generate
создает неупорядоченный поток :
Возвращает бесконечный последовательный неупорядоченный поток, в котором каждый элемент генерируется предоставленным Поставщиком.
Это подходит для генерации постоянных потоков, потоков случайных элементов и т. Д.
Вы не возвращаете постоянные или случайные значения, а также все, что не зависит от порядка.
Это оказывает существенное влияние на семантику takeWhile
:
В противном случае возвращает, если этот поток неупорядоченный, поток, состоящий из подмножества элементов, взятых из этого потока, которые соответствуют данному предикату.
Это имеет смысл, если вы думаете об этом. Если есть хотя бы один элемент, отклоненный предикатом, он может встретиться в произвольной позиции для потока неупорядоченного , поэтому любое допустимое подмножество элементов, встречающихся перед ним, включая пустой набор, будет допустимым приставка.
Но поскольку для неупорядоченного потока нет «до» или «после», даже элементы, созданные генератором после , в результат может быть включен отклоненный элемент.
На практике вы вряд ли столкнетесь с такими эффектами для последовательного потока, но это не меняет того факта, что Stream.generate(…) .takeWhile(…)
семантически неверен для вашей задачи.
Исходя из вашего примера кода, я заключаю, что страницы не содержат ни своего собственного номера, ни метода "getNext", поэтому мы должны сохранить номер и состояние "hasNext" для создания потока.
Предполагается пример настройки, такой как
class Page {
private String data;
private boolean hasNext;
public Page(String data, boolean hasNext) {
this.data = data;
this.hasNext = hasNext;
}
public String getData() {
return data;
}
public boolean hasNext() {
return hasNext;
}
}
private static String[] SAMPLE_PAGES = { "foo", "bar", "baz" };
public static Page getPage(int index) {
Objects.checkIndex(index, SAMPLE_PAGES.length);
return new Page(SAMPLE_PAGES[index], index + 1 < SAMPLE_PAGES.length);
}
Вы можете реализовать правильный поток, такой как
Stream.iterate(Map.entry(0, getPage(0)), Objects::nonNull,
e -> e.getValue().hasNext()? Map.entry(e.getKey()+1, getPage(e.getKey()+1)): null)
.map(Map.Entry::getValue)
.forEach(page -> System.out.println(page.getData()));
Обратите внимание, что Stream.iterate
создает заказанный поток :
Возвращает последовательный упорядоченный поток, созданный итеративным применением данной следующей функции к начальному элементу,
при условии выполнения заданного предиката hasNext.
Конечно, было бы намного проще, если бы страница знала свой номер, например,
Stream.iterate(getPage(0), Objects::nonNull,
p -> p.hasNext()? getPage(p.getPageNumber()+1): null)
.forEach(page -> System.out.println(page.getData()));
или если существовал метод для перехода с существующей страницы на следующую страницу, например,
Stream.iterate(getPage(0), Objects::nonNull, p -> p.hasNext()? p.getNextPage(): null)
.forEach(page -> System.out.println(page.getData()));