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.functor.core.collection;
018    
019    import java.util.Iterator;
020    import java.util.NoSuchElementException;
021    
022    import org.apache.commons.functor.UnaryPredicate;
023    
024    /**
025     * Iterator that filters another Iterator by only passing through those elements
026     * that are matched by a specified UnaryPredicate.
027     * @version $Revision: 1156789 $ $Date: 2011-08-11 22:05:09 +0200 (Thu, 11 Aug 2011) $
028     * @author Rodney Waldhoff
029     */
030    public final class FilteredIterator<T> implements Iterator<T> {
031        // attributes
032        // ------------------------------------------------------------------------
033    
034        private final UnaryPredicate<? super T> predicate;
035        private final Iterator<? extends T> iterator;
036    
037        private T next = null;
038        private boolean nextSet = false;
039        private boolean canRemove = false;
040    
041        // constructor
042        // ------------------------------------------------------------------------
043        /**
044         * Create a new FilteredIterator.
045         * @param iterator to filter
046         * @param predicate to apply
047         */
048        public FilteredIterator(Iterator<? extends T> iterator, UnaryPredicate<? super T> predicate) {
049            if (null == iterator) {
050                throw new IllegalArgumentException("Iterator argument was null");
051            }
052            if (null == predicate) {
053                throw new IllegalArgumentException("filtering UnaryPredicate argument was null");
054            }
055            this.predicate = predicate;
056            this.iterator = iterator;
057        }
058    
059        // iterator methods
060        // ------------------------------------------------------------------------
061    
062        /**
063         * {@inheritDoc}
064         * @see java.util.Iterator#hasNext()
065         */
066        public boolean hasNext() {
067            return nextSet || setNext();
068        }
069    
070        /**
071         * {@inheritDoc}
072         * @see java.util.Iterator#next()
073         */
074        public T next() {
075            if (hasNext()) {
076                return returnNext();
077            }
078            throw new NoSuchElementException();
079        }
080    
081        /**
082         * {@inheritDoc}
083         * @see java.util.Iterator#remove()
084         */
085        public void remove() {
086            if (canRemove) {
087                canRemove = false;
088                iterator.remove();
089            } else {
090                throw new IllegalStateException();
091            }
092        }
093    
094        /**
095         * {@inheritDoc}
096         */
097        public boolean equals(Object obj) {
098            if (obj == this) {
099                return true;
100            }
101            if (!(obj instanceof FilteredIterator<?>)) {
102                return false;
103            }
104            FilteredIterator<?> that = (FilteredIterator<?>) obj;
105            return predicate.equals(that.predicate) && iterator.equals(that.iterator);
106        }
107    
108        /**
109         * {@inheritDoc}
110         */
111        public int hashCode() {
112            int hash = "FilteredIterator".hashCode();
113            hash <<= 2;
114            hash ^= predicate.hashCode();
115            hash <<= 2;
116            hash ^= iterator.hashCode();
117            return hash;
118        }
119    
120        /**
121         * {@inheritDoc}
122         */
123        public String toString() {
124            return "FilteredIterator<" + iterator + "," + predicate + ">";
125        }
126    
127        // static methods
128        // ------------------------------------------------------------------------
129        /**
130         * Get a filtered Iterator instance applying <code>pred</code> to <code>iter</code>.
131         * @param iter to filter
132         * @param pred to apply
133         * @return Iterator
134         */
135        @SuppressWarnings("unchecked")
136        public static <T> Iterator<T> filter(Iterator<? extends T> iter, UnaryPredicate<? super T> pred) {
137            return null == pred ? (Iterator<T>) iter : (null == iter ? null : new FilteredIterator<T>(iter, pred));
138        }
139    
140        // private
141        // ------------------------------------------------------------------------
142        /**
143         * Set next element.
144         * @return whether the current iterator position is valid
145         */
146        private boolean setNext() {
147            while (iterator.hasNext()) {
148                canRemove = false;
149                T obj = iterator.next();
150                if (predicate.test(obj)) {
151                    nextSet = true;
152                    next = obj;
153                    return true;
154                }
155            }
156            next = null;
157            nextSet = false;
158            return false;
159        }
160    
161        /**
162         * Get the next element.
163         * @return next element.
164         */
165        private T returnNext() {
166            T temp = next;
167            canRemove = true;
168            next = null;
169            nextSet = false;
170            return temp;
171        }
172    
173    }