public IterationResult<T> iterate(@Nonnull UUID cursorId, int maxCount) {
        requireNonNull(cursorId);
        if (cursorId.equals(this.prevCursorId)) {
            access();
            // no progress, no need to forget a cursor id, so null
            return new IterationResult<>(this.page, this.cursorId, null);
        } else if (!cursorId.equals(this.cursorId)) {
            throw new IllegalStateException("The cursor id " + cursorId
                    + " is not the current cursor id nor the previous cursor id.");
        }
        List<T> currentPage = new ArrayList<>(maxCount);
        while (currentPage.size() < maxCount && iterator.hasNext()) {
            currentPage.add(iterator.next());
        }
        UUID cursorIdToForget = this.prevCursorId;
        this.prevCursorId = this.cursorId;
        this.cursorId = UuidUtil.newUnsecureUUID();
        this.page = currentPage;
        access();
        return new IterationResult<>(this.page, this.cursorId, cursorIdToForget);
    }
@Test
    public void testCursorIdOtherThan_PreviousOrCurrent_Throws() {
        UUID cursorId = iterator.iterate(initialCursorId, 100).getCursorId();
        iterator.iterate(cursorId, 100);
        // prevCursorId == cursorId, cursorId == new id
        assertThatThrownBy(() -> iterator.iterate(initialCursorId, 100)).isInstanceOf(IllegalStateException.class)
                .hasMessageContaining("The cursor id " + initialCursorId
                        + " is not the current cursor id nor the previous cursor id.");
    }