1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.collections4.iterators;
18
19 import java.util.Iterator;
20
21 /**
22 * Decorates another iterator to skip the first N elements.
23 * <p>
24 * In case an offset parameter other than 0 is provided, the decorated
25 * iterator is immediately advanced to this position, skipping all elements
26 * before that position.
27 * </p>
28 *
29 * @param <E> the type of elements returned by this iterator.
30 * @since 4.1
31 */
32 public class SkippingIterator<E> extends AbstractIteratorDecorator<E> {
33
34 /** The offset to bound the first element return */
35 private final long offset;
36
37 /** The position of the current element */
38 private long pos;
39
40 /**
41 * Decorates the specified iterator to skip all elements until the iterator
42 * reaches the position at {@code offset}.
43 * <p>
44 * The iterator is immediately advanced until it reaches the position at {@code offset},
45 * incurring O(n) time.
46 *
47 * @param iterator the iterator to be decorated
48 * @param offset the index of the first element of the decorated iterator to return
49 * @throws NullPointerException if iterator is null
50 * @throws IllegalArgumentException if offset is negative
51 */
52 public SkippingIterator(final Iterator<E> iterator, final long offset) {
53 super(iterator);
54
55 if (offset < 0) {
56 throw new IllegalArgumentException("Offset parameter must not be negative.");
57 }
58
59 this.offset = offset;
60 this.pos = 0;
61 init();
62 }
63
64 /**
65 * Skips the given number of elements.
66 */
67 private void init() {
68 while (pos < offset && hasNext()) {
69 next();
70 }
71 }
72
73 @Override
74 public E next() {
75 final E next = super.next();
76 pos++;
77 return next;
78 }
79
80 /**
81 * {@inheritDoc}
82 * <p>
83 * In case an offset other than 0 was specified, the underlying iterator will be advanced
84 * to this position upon creation. A call to {@link #remove()} will still result in an
85 * {@link IllegalStateException} if no explicit call to {@link #next()} has been made prior
86 * to calling {@link #remove()}.
87 */
88 @Override
89 public void remove() {
90 if (pos <= offset) {
91 throw new IllegalStateException("remove() cannot be called before calling next()");
92 }
93 super.remove();
94 }
95
96 }