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.ListIterator;
20  import java.util.NoSuchElementException;
21  
22  import org.apache.commons.collections.Predicate;
23  
24  /** 
25   * Decorates another {@link ListIterator} 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 2.0
31   * @version $Id: FilterListIterator.java 1429905 2013-01-07 17:15:14Z ggregory $
32   */
33  public class FilterListIterator<E> implements ListIterator<E> {
34  
35      /** The iterator being used */
36      private ListIterator<? extends E> iterator;
37      
38      /** The predicate being used */
39      private Predicate<? super E> predicate;
40  
41      /** 
42       * The value of the next (matching) object, when 
43       * {@link #nextObjectSet} is true. 
44       */
45      private E nextObject;
46  
47      /** 
48       * Whether or not the {@link #nextObject} has been set
49       * (possibly to <code>null</code>). 
50       */
51      private boolean nextObjectSet = false;   
52  
53      /** 
54       * The value of the previous (matching) object, when 
55       * {@link #previousObjectSet} is true. 
56       */
57      private E previousObject;
58  
59      /** 
60       * Whether or not the {@link #previousObject} has been set
61       * (possibly to <code>null</code>). 
62       */
63      private boolean previousObjectSet = false;   
64  
65      /** 
66       * The index of the element that would be returned by {@link #next}.
67       */
68      private int nextIndex = 0;
69      
70      //-----------------------------------------------------------------------
71      /**
72       * Constructs a new <code>FilterListIterator</code> that will not function
73       * until {@link #setListIterator(ListIterator) setListIterator}
74       * and {@link #setPredicate(Predicate) setPredicate} are invoked.
75       */
76      public FilterListIterator() {
77          super();
78      }
79  
80      /**
81       * Constructs a new <code>FilterListIterator</code> that will not 
82       * function until {@link #setPredicate(Predicate) setPredicate} is invoked.
83       *
84       * @param iterator  the iterator to use
85       */
86      public FilterListIterator(final ListIterator<? extends E> iterator ) {
87          super();
88          this.iterator = iterator;
89      }
90  
91      /**
92       * Constructs a new <code>FilterListIterator</code>.
93       *
94       * @param iterator  the iterator to use
95       * @param predicate  the predicate to use
96       */
97      public FilterListIterator(final ListIterator<? extends E> iterator, final Predicate<? super E> predicate) {
98          super();
99          this.iterator = iterator;
100         this.predicate = predicate;
101     }
102 
103     /**
104      * Constructs a new <code>FilterListIterator</code> that will not function
105      * until {@link #setListIterator(ListIterator) setListIterator} is invoked.
106      *
107      * @param predicate  the predicate to use.
108      */
109     public FilterListIterator(final Predicate<? super E> predicate) {
110         super();
111         this.predicate = predicate;
112     }
113 
114     //-----------------------------------------------------------------------
115     /** Not supported. */
116     public void add(final E o) {
117         throw new UnsupportedOperationException("FilterListIterator.add(Object) is not supported.");
118     }
119 
120     public boolean hasNext() {
121         return nextObjectSet || setNextObject();
122     }
123 
124     public boolean hasPrevious() {
125         return previousObjectSet || setPreviousObject();
126     }
127 
128     public E next() {
129         if (!nextObjectSet) {
130             if (!setNextObject()) {
131                 throw new NoSuchElementException();
132             }
133         }
134         nextIndex++;
135         final E temp = nextObject;
136         clearNextObject();
137         return temp;
138     }
139 
140     public int nextIndex() {
141         return nextIndex;
142     }
143 
144     public E previous() {
145         if (!previousObjectSet) {
146             if (!setPreviousObject()) {
147                 throw new NoSuchElementException();
148             }
149         }
150         nextIndex--;
151         final E temp = previousObject;
152         clearPreviousObject();
153         return temp;
154     }
155 
156     public int previousIndex() {
157         return nextIndex-1;
158     }
159 
160     /** Not supported. */
161     public void remove() {
162         throw new UnsupportedOperationException("FilterListIterator.remove() is not supported.");
163     }
164 
165     /** Not supported. */
166     public void set(final E o) {
167         throw new UnsupportedOperationException("FilterListIterator.set(Object) is not supported.");
168     }
169 
170     //-----------------------------------------------------------------------
171     /** 
172      * Gets the iterator this iterator is using.
173      * 
174      * @return the iterator.
175      */
176     public ListIterator<? extends E> getListIterator() {
177         return iterator;
178     }
179 
180     /** 
181      * Sets the iterator for this iterator to use.
182      * If iteration has started, this effectively resets the iterator.
183      * 
184      * @param iterator  the iterator to use
185      */
186     public void setListIterator(final ListIterator<? extends E> iterator) {
187         this.iterator = iterator;
188     }
189 
190     //-----------------------------------------------------------------------
191     /** 
192      * Gets the predicate this iterator is using.
193      * 
194      * @return the predicate.
195      */
196     public Predicate<? super E> getPredicate() {
197         return predicate;
198     }
199 
200     /** 
201      * Sets the predicate this the iterator to use.
202      * 
203      * @param predicate  the transformer to use
204      */
205     public void setPredicate(final Predicate<? super E> predicate) {
206         this.predicate = predicate;
207     }
208 
209     //-----------------------------------------------------------------------
210     private void clearNextObject() {
211         nextObject = null;
212         nextObjectSet = false;
213     }
214 
215     private boolean setNextObject() {
216         // if previousObjectSet,
217         // then we've walked back one step in the 
218         // underlying list (due to a hasPrevious() call)
219         // so skip ahead one matching object
220         if (previousObjectSet) {
221             clearPreviousObject();
222             if (!setNextObject()) {
223                 return false;
224             }
225             clearNextObject();
226         }
227 
228         if (iterator == null) {
229             return false;
230         }
231         while (iterator.hasNext()) {
232             final E object = iterator.next();
233             if (predicate.evaluate(object)) {
234                 nextObject = object;
235                 nextObjectSet = true;
236                 return true;
237             }
238         }
239         return false;
240     }
241 
242     private void clearPreviousObject() {
243         previousObject = null;
244         previousObjectSet = false;
245     }
246 
247     private boolean setPreviousObject() {
248         // if nextObjectSet,
249         // then we've walked back one step in the 
250         // underlying list (due to a hasNext() call)
251         // so skip ahead one matching object
252         if (nextObjectSet) {
253             clearNextObject();
254             if (!setPreviousObject()) {
255                 return false;
256             }
257             clearPreviousObject();
258         }
259 
260         if (iterator == null) {
261             return false;
262         }
263         while (iterator.hasPrevious()) {
264             final E object = iterator.previous();
265             if (predicate.evaluate(object)) {
266                 previousObject = object;
267                 previousObjectSet = true;
268                 return true;
269             }
270         }
271         return false;
272     }
273 
274 }