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.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 }