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.collections.iterators; 018 019 import java.util.Iterator; 020 import java.util.NoSuchElementException; 021 022 import org.apache.commons.collections.Predicate; 023 024 /** 025 * Decorates another {@link Iterator} using a predicate to filter elements. 026 * <p> 027 * This iterator decorates the underlying iterator, only allowing through 028 * those elements that match the specified {@link Predicate Predicate}. 029 * 030 * @since Commons Collections 1.0 031 * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $ 032 * 033 * @author James Strachan 034 * @author Jan Sorensen 035 * @author Ralph Wagner 036 * @author Stephen Colebourne 037 */ 038 public class FilterIterator implements Iterator { 039 040 /** The iterator being used */ 041 private Iterator iterator; 042 /** The predicate being used */ 043 private Predicate predicate; 044 /** The next object in the iteration */ 045 private Object nextObject; 046 /** Whether the next object has been calculated yet */ 047 private boolean nextObjectSet = false; 048 049 //----------------------------------------------------------------------- 050 /** 051 * Constructs a new <code>FilterIterator</code> that will not function 052 * until {@link #setIterator(Iterator) setIterator} is invoked. 053 */ 054 public FilterIterator() { 055 super(); 056 } 057 058 /** 059 * Constructs a new <code>FilterIterator</code> that will not function 060 * until {@link #setPredicate(Predicate) setPredicate} is invoked. 061 * 062 * @param iterator the iterator to use 063 */ 064 public FilterIterator(Iterator iterator) { 065 super(); 066 this.iterator = iterator; 067 } 068 069 /** 070 * Constructs a new <code>FilterIterator</code> that will use the 071 * given iterator and predicate. 072 * 073 * @param iterator the iterator to use 074 * @param predicate the predicate to use 075 */ 076 public FilterIterator(Iterator iterator, Predicate predicate) { 077 super(); 078 this.iterator = iterator; 079 this.predicate = predicate; 080 } 081 082 //----------------------------------------------------------------------- 083 /** 084 * Returns true if the underlying iterator contains an object that 085 * matches the predicate. 086 * 087 * @return true if there is another object that matches the predicate 088 * @throws NullPointerException if either the iterator or predicate are null 089 */ 090 public boolean hasNext() { 091 if (nextObjectSet) { 092 return true; 093 } else { 094 return setNextObject(); 095 } 096 } 097 098 /** 099 * Returns the next object that matches the predicate. 100 * 101 * @return the next object which matches the given predicate 102 * @throws NullPointerException if either the iterator or predicate are null 103 * @throws NoSuchElementException if there are no more elements that 104 * match the predicate 105 */ 106 public Object next() { 107 if (!nextObjectSet) { 108 if (!setNextObject()) { 109 throw new NoSuchElementException(); 110 } 111 } 112 nextObjectSet = false; 113 return nextObject; 114 } 115 116 /** 117 * Removes from the underlying collection of the base iterator the last 118 * element returned by this iterator. 119 * This method can only be called 120 * if <code>next()</code> was called, but not after 121 * <code>hasNext()</code>, because the <code>hasNext()</code> call 122 * changes the base iterator. 123 * 124 * @throws IllegalStateException if <code>hasNext()</code> has already 125 * been called. 126 */ 127 public void remove() { 128 if (nextObjectSet) { 129 throw new IllegalStateException("remove() cannot be called"); 130 } 131 iterator.remove(); 132 } 133 134 //----------------------------------------------------------------------- 135 /** 136 * Gets the iterator this iterator is using. 137 * 138 * @return the iterator 139 */ 140 public Iterator getIterator() { 141 return iterator; 142 } 143 144 /** 145 * Sets the iterator for this iterator to use. 146 * If iteration has started, this effectively resets the iterator. 147 * 148 * @param iterator the iterator to use 149 */ 150 public void setIterator(Iterator iterator) { 151 this.iterator = iterator; 152 nextObject = null; 153 nextObjectSet = false; 154 } 155 156 //----------------------------------------------------------------------- 157 /** 158 * Gets the predicate this iterator is using. 159 * 160 * @return the predicate 161 */ 162 public Predicate getPredicate() { 163 return predicate; 164 } 165 166 /** 167 * Sets the predicate this the iterator to use. 168 * 169 * @param predicate the predicate to use 170 */ 171 public void setPredicate(Predicate predicate) { 172 this.predicate = predicate; 173 nextObject = null; 174 nextObjectSet = false; 175 } 176 177 //----------------------------------------------------------------------- 178 /** 179 * Set nextObject to the next object. If there are no more 180 * objects then return false. Otherwise, return true. 181 */ 182 private boolean setNextObject() { 183 while (iterator.hasNext()) { 184 Object object = iterator.next(); 185 if (predicate.evaluate(object)) { 186 nextObject = object; 187 nextObjectSet = true; 188 return true; 189 } 190 } 191 return false; 192 } 193 194 }