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