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.Iterator;
020 import java.util.NoSuchElementException;
021
022 import org.apache.commons.collections.Predicate;
023
024 /**
025 * Decorates another {@link Iterator} using a predicate to filter elements.
026 * <p>
027 * This iterator decorates the underlying iterator, only allowing through
028 * those elements that match the specified {@link Predicate Predicate}.
029 *
030 * @since Commons Collections 1.0
031 * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
032 *
033 * @author James Strachan
034 * @author Jan Sorensen
035 * @author Ralph Wagner
036 * @author Stephen Colebourne
037 */
038 public class FilterIterator implements Iterator {
039
040 /** The iterator being used */
041 private Iterator iterator;
042 /** The predicate being used */
043 private Predicate predicate;
044 /** The next object in the iteration */
045 private Object nextObject;
046 /** Whether the next object has been calculated yet */
047 private boolean nextObjectSet = false;
048
049 //-----------------------------------------------------------------------
050 /**
051 * Constructs a new <code>FilterIterator</code> that will not function
052 * until {@link #setIterator(Iterator) setIterator} is invoked.
053 */
054 public FilterIterator() {
055 super();
056 }
057
058 /**
059 * Constructs a new <code>FilterIterator</code> that will not function
060 * until {@link #setPredicate(Predicate) setPredicate} is invoked.
061 *
062 * @param iterator the iterator to use
063 */
064 public FilterIterator(Iterator iterator) {
065 super();
066 this.iterator = iterator;
067 }
068
069 /**
070 * Constructs a new <code>FilterIterator</code> that will use the
071 * given iterator and predicate.
072 *
073 * @param iterator the iterator to use
074 * @param predicate the predicate to use
075 */
076 public FilterIterator(Iterator iterator, Predicate predicate) {
077 super();
078 this.iterator = iterator;
079 this.predicate = predicate;
080 }
081
082 //-----------------------------------------------------------------------
083 /**
084 * Returns true if the underlying iterator contains an object that
085 * matches the predicate.
086 *
087 * @return true if there is another object that matches the predicate
088 * @throws NullPointerException if either the iterator or predicate are null
089 */
090 public boolean hasNext() {
091 if (nextObjectSet) {
092 return true;
093 } else {
094 return setNextObject();
095 }
096 }
097
098 /**
099 * Returns the next object that matches the predicate.
100 *
101 * @return the next object which matches the given predicate
102 * @throws NullPointerException if either the iterator or predicate are null
103 * @throws NoSuchElementException if there are no more elements that
104 * match the predicate
105 */
106 public Object next() {
107 if (!nextObjectSet) {
108 if (!setNextObject()) {
109 throw new NoSuchElementException();
110 }
111 }
112 nextObjectSet = false;
113 return nextObject;
114 }
115
116 /**
117 * Removes from the underlying collection of the base iterator the last
118 * element returned by this iterator.
119 * This method can only be called
120 * if <code>next()</code> was called, but not after
121 * <code>hasNext()</code>, because the <code>hasNext()</code> call
122 * changes the base iterator.
123 *
124 * @throws IllegalStateException if <code>hasNext()</code> has already
125 * been called.
126 */
127 public void remove() {
128 if (nextObjectSet) {
129 throw new IllegalStateException("remove() cannot be called");
130 }
131 iterator.remove();
132 }
133
134 //-----------------------------------------------------------------------
135 /**
136 * Gets the iterator this iterator is using.
137 *
138 * @return the iterator
139 */
140 public Iterator getIterator() {
141 return iterator;
142 }
143
144 /**
145 * Sets the iterator for this iterator to use.
146 * If iteration has started, this effectively resets the iterator.
147 *
148 * @param iterator the iterator to use
149 */
150 public void setIterator(Iterator iterator) {
151 this.iterator = iterator;
152 nextObject = null;
153 nextObjectSet = false;
154 }
155
156 //-----------------------------------------------------------------------
157 /**
158 * Gets the predicate this iterator is using.
159 *
160 * @return the predicate
161 */
162 public Predicate getPredicate() {
163 return predicate;
164 }
165
166 /**
167 * Sets the predicate this the iterator to use.
168 *
169 * @param predicate the predicate to use
170 */
171 public void setPredicate(Predicate predicate) {
172 this.predicate = predicate;
173 nextObject = null;
174 nextObjectSet = false;
175 }
176
177 //-----------------------------------------------------------------------
178 /**
179 * Set nextObject to the next object. If there are no more
180 * objects then return false. Otherwise, return true.
181 */
182 private boolean setNextObject() {
183 while (iterator.hasNext()) {
184 Object object = iterator.next();
185 if (predicate.evaluate(object)) {
186 nextObject = object;
187 nextObjectSet = true;
188 return true;
189 }
190 }
191 return false;
192 }
193
194 }