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.collections.iterators;
18
19 import java.util.Iterator;
20 import java.util.NoSuchElementException;
21
22 import org.apache.commons.collections.Predicate;
23
24 /**
25 * Decorates another {@link Iterator} using a predicate to filter elements.
26 * <p>
27 * This iterator decorates the underlying iterator, only allowing through
28 * those elements that match the specified {@link Predicate Predicate}.
29 *
30 * @since 1.0
31 * @version $Id: FilterIterator.java 1429905 2013-01-07 17:15:14Z ggregory $
32 */
33 public class FilterIterator<E> implements Iterator<E> {
34
35 /** The iterator being used */
36 private Iterator<? extends E> iterator;
37 /** The predicate being used */
38 private Predicate<? super E> predicate;
39 /** The next object in the iteration */
40 private E nextObject;
41 /** Whether the next object has been calculated yet */
42 private boolean nextObjectSet = false;
43
44 //-----------------------------------------------------------------------
45 /**
46 * Constructs a new <code>FilterIterator</code> that will not function
47 * until {@link #setIterator(Iterator) setIterator} is invoked.
48 */
49 public FilterIterator() {
50 super();
51 }
52
53 /**
54 * Constructs a new <code>FilterIterator</code> that will not function
55 * until {@link #setPredicate(Predicate) setPredicate} is invoked.
56 *
57 * @param iterator the iterator to use
58 */
59 public FilterIterator(final Iterator<? extends E> iterator) {
60 super();
61 this.iterator = iterator;
62 }
63
64 /**
65 * Constructs a new <code>FilterIterator</code> that will use the
66 * given iterator and predicate.
67 *
68 * @param iterator the iterator to use
69 * @param predicate the predicate to use
70 */
71 public FilterIterator(final Iterator<? extends E> iterator, final Predicate<? super E> predicate) {
72 super();
73 this.iterator = iterator;
74 this.predicate = predicate;
75 }
76
77 //-----------------------------------------------------------------------
78 /**
79 * Returns true if the underlying iterator contains an object that
80 * matches the predicate.
81 *
82 * @return true if there is another object that matches the predicate
83 * @throws NullPointerException if either the iterator or predicate are null
84 */
85 public boolean hasNext() {
86 return nextObjectSet || setNextObject();
87 }
88
89 /**
90 * Returns the next object that matches the predicate.
91 *
92 * @return the next object which matches the given predicate
93 * @throws NullPointerException if either the iterator or predicate are null
94 * @throws NoSuchElementException if there are no more elements that
95 * match the predicate
96 */
97 public E next() {
98 if (!nextObjectSet) {
99 if (!setNextObject()) {
100 throw new NoSuchElementException();
101 }
102 }
103 nextObjectSet = false;
104 return nextObject;
105 }
106
107 /**
108 * Removes from the underlying collection of the base iterator the last
109 * element returned by this iterator.
110 * This method can only be called
111 * if <code>next()</code> was called, but not after
112 * <code>hasNext()</code>, because the <code>hasNext()</code> call
113 * changes the base iterator.
114 *
115 * @throws IllegalStateException if <code>hasNext()</code> has already
116 * been called.
117 */
118 public void remove() {
119 if (nextObjectSet) {
120 throw new IllegalStateException("remove() cannot be called");
121 }
122 iterator.remove();
123 }
124
125 //-----------------------------------------------------------------------
126 /**
127 * Gets the iterator this iterator is using.
128 *
129 * @return the iterator
130 */
131 public Iterator<? extends E> getIterator() {
132 return iterator;
133 }
134
135 /**
136 * Sets the iterator for this iterator to use.
137 * If iteration has started, this effectively resets the iterator.
138 *
139 * @param iterator the iterator to use
140 */
141 public void setIterator(final Iterator<? extends E> iterator) {
142 this.iterator = iterator;
143 nextObject = null;
144 nextObjectSet = false;
145 }
146
147 //-----------------------------------------------------------------------
148 /**
149 * Gets the predicate this iterator is using.
150 *
151 * @return the predicate
152 */
153 public Predicate<? super E> getPredicate() {
154 return predicate;
155 }
156
157 /**
158 * Sets the predicate this the iterator to use.
159 *
160 * @param predicate the predicate to use
161 */
162 public void setPredicate(final Predicate<? super E> predicate) {
163 this.predicate = predicate;
164 nextObject = null;
165 nextObjectSet = false;
166 }
167
168 //-----------------------------------------------------------------------
169 /**
170 * Set nextObject to the next object. If there are no more
171 * objects then return false. Otherwise, return true.
172 */
173 private boolean setNextObject() {
174 while (iterator.hasNext()) {
175 final E object = iterator.next();
176 if (predicate.evaluate(object)) {
177 nextObject = object;
178 nextObjectSet = true;
179 return true;
180 }
181 }
182 return false;
183 }
184
185 }