001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with this 004 * work for additional information regarding copyright ownership. The ASF 005 * licenses this file to You under the Apache License, Version 2.0 (the 006 * "License"); you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law 009 * or agreed to in writing, software distributed under the License is 010 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 011 * KIND, either express or implied. See the License for the specific language 012 * governing permissions and limitations under the License. 013 */ 014package org.apache.commons.collections4.iterators; 015 016import java.util.Iterator; 017 018/** 019 * Decorates another iterator to skip the first N elements. 020 * <p> 021 * In case an offset parameter other than 0 is provided, the decorated 022 * iterator is immediately advanced to this position, skipping all elements 023 * before that position. 024 * 025 * @since 4.1 026 */ 027public class SkippingIterator<E> extends AbstractIteratorDecorator<E> { 028 029 /** The offset to bound the first element return */ 030 private final long offset; 031 032 /** The position of the current element */ 033 private long pos; 034 035 //----------------------------------------------------------------------- 036 037 /** 038 * Decorates the specified iterator to skip all elements until the iterator 039 * reaches the position at {@code offset}. 040 * <p> 041 * The iterator is immediately advanced until it reaches the position at {@code offset}, 042 * incurring O(n) time. 043 * 044 * @param iterator the iterator to be decorated 045 * @param offset the index of the first element of the decorated iterator to return 046 * @throws NullPointerException if iterator is null 047 * @throws IllegalArgumentException if offset is negative 048 */ 049 public SkippingIterator(final Iterator<E> iterator, final long offset) { 050 super(iterator); 051 052 if (offset < 0) { 053 throw new IllegalArgumentException("Offset parameter must not be negative."); 054 } 055 056 this.offset = offset; 057 this.pos = 0; 058 init(); 059 } 060 061 /** 062 * Skips the given number of elements. 063 */ 064 private void init() { 065 while (pos < offset && hasNext()) { 066 next(); 067 } 068 } 069 070 //----------------------------------------------------------------------- 071 072 @Override 073 public E next() { 074 final E next = super.next(); 075 pos++; 076 return next; 077 } 078 079 /** 080 * {@inheritDoc} 081 * <p> 082 * In case an offset other than 0 was specified, the underlying iterator will be advanced 083 * to this position upon creation. A call to {@link #remove()} will still result in an 084 * {@link IllegalStateException} if no explicit call to {@link #next()} has been made prior 085 * to calling {@link #remove()}. 086 */ 087 @Override 088 public void remove() { 089 if (pos <= offset) { 090 throw new IllegalStateException("remove() can not be called before calling next()"); 091 } 092 super.remove(); 093 } 094 095}