001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.collections.iterators; 018 019 import java.util.Collection; 020 import java.util.Iterator; 021 import java.util.NoSuchElementException; 022 023 import org.apache.commons.collections.ResettableIterator; 024 025 /** 026 * An Iterator that restarts when it reaches the end. 027 * <p> 028 * The iterator will loop continuously around the provided elements, unless 029 * there are no elements in the collection to begin with, or all the elements 030 * have been {@link #remove removed}. 031 * <p> 032 * Concurrent modifications are not directly supported, and for most collection 033 * implementations will throw a ConcurrentModificationException. 034 * 035 * @since Commons Collections 3.0 036 * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $ 037 * 038 * @author <a href="mailto:joncrlsn@users.sf.net">Jonathan Carlson</a> 039 * @author Stephen Colebourne 040 */ 041 public class LoopingIterator implements ResettableIterator { 042 043 /** The collection to base the iterator on */ 044 private Collection collection; 045 /** The current iterator */ 046 private Iterator iterator; 047 048 /** 049 * Constructor that wraps a collection. 050 * <p> 051 * There is no way to reset an Iterator instance without recreating it from 052 * the original source, so the Collection must be passed in. 053 * 054 * @param coll the collection to wrap 055 * @throws NullPointerException if the collection is null 056 */ 057 public LoopingIterator(Collection coll) { 058 if (coll == null) { 059 throw new NullPointerException("The collection must not be null"); 060 } 061 collection = coll; 062 reset(); 063 } 064 065 /** 066 * Has the iterator any more elements. 067 * <p> 068 * Returns false only if the collection originally had zero elements, or 069 * all the elements have been {@link #remove removed}. 070 * 071 * @return <code>true</code> if there are more elements 072 */ 073 public boolean hasNext() { 074 return (collection.size() > 0); 075 } 076 077 /** 078 * Returns the next object in the collection. 079 * <p> 080 * If at the end of the collection, return the first element. 081 * 082 * @throws NoSuchElementException if there are no elements 083 * at all. Use {@link #hasNext} to avoid this error. 084 */ 085 public Object next() { 086 if (collection.size() == 0) { 087 throw new NoSuchElementException("There are no elements for this iterator to loop on"); 088 } 089 if (iterator.hasNext() == false) { 090 reset(); 091 } 092 return iterator.next(); 093 } 094 095 /** 096 * Removes the previously retrieved item from the underlying collection. 097 * <p> 098 * This feature is only supported if the underlying collection's 099 * {@link Collection#iterator iterator} method returns an implementation 100 * that supports it. 101 * <p> 102 * This method can only be called after at least one {@link #next} method call. 103 * After a removal, the remove method may not be called again until another 104 * next has been performed. If the {@link #reset} is called, then remove may 105 * not be called until {@link #next} is called again. 106 */ 107 public void remove() { 108 iterator.remove(); 109 } 110 111 /** 112 * Resets the iterator back to the start of the collection. 113 */ 114 public void reset() { 115 iterator = collection.iterator(); 116 } 117 118 /** 119 * Gets the size of the collection underlying the iterator. 120 * 121 * @return the current collection size 122 */ 123 public int size() { 124 return collection.size(); 125 } 126 127 }