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 */ 017package org.apache.commons.collections4.iterators; 018 019import java.util.ListIterator; 020import java.util.NoSuchElementException; 021 022import org.apache.commons.collections4.Predicate; 023 024/** 025 * Decorates another {@link ListIterator} 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 2.0 031 */ 032public class FilterListIterator<E> implements ListIterator<E> { 033 034 /** The iterator being used */ 035 private ListIterator<? extends E> iterator; 036 037 /** The predicate being used */ 038 private Predicate<? super E> predicate; 039 040 /** 041 * The value of the next (matching) object, when 042 * {@link #nextObjectSet} is true. 043 */ 044 private E nextObject; 045 046 /** 047 * Whether or not the {@link #nextObject} has been set 048 * (possibly to <code>null</code>). 049 */ 050 private boolean nextObjectSet = false; 051 052 /** 053 * The value of the previous (matching) object, when 054 * {@link #previousObjectSet} is true. 055 */ 056 private E previousObject; 057 058 /** 059 * Whether or not the {@link #previousObject} has been set 060 * (possibly to <code>null</code>). 061 */ 062 private boolean previousObjectSet = false; 063 064 /** 065 * The index of the element that would be returned by {@link #next}. 066 */ 067 private int nextIndex = 0; 068 069 //----------------------------------------------------------------------- 070 /** 071 * Constructs a new <code>FilterListIterator</code> that will not function 072 * until {@link #setListIterator(ListIterator) setListIterator} 073 * and {@link #setPredicate(Predicate) setPredicate} are invoked. 074 */ 075 public FilterListIterator() { 076 super(); 077 } 078 079 /** 080 * Constructs a new <code>FilterListIterator</code> that will not 081 * function until {@link #setPredicate(Predicate) setPredicate} is invoked. 082 * 083 * @param iterator the iterator to use 084 */ 085 public FilterListIterator(final ListIterator<? extends E> iterator ) { 086 super(); 087 this.iterator = iterator; 088 } 089 090 /** 091 * Constructs a new <code>FilterListIterator</code>. 092 * 093 * @param iterator the iterator to use 094 * @param predicate the predicate to use 095 */ 096 public FilterListIterator(final ListIterator<? extends E> iterator, final Predicate<? super E> predicate) { 097 super(); 098 this.iterator = iterator; 099 this.predicate = predicate; 100 } 101 102 /** 103 * Constructs a new <code>FilterListIterator</code> that will not function 104 * until {@link #setListIterator(ListIterator) setListIterator} is invoked. 105 * 106 * @param predicate the predicate to use. 107 */ 108 public FilterListIterator(final Predicate<? super E> predicate) { 109 super(); 110 this.predicate = predicate; 111 } 112 113 //----------------------------------------------------------------------- 114 /** 115 * Not supported. 116 * @param o the element to insert 117 */ 118 @Override 119 public void add(final E o) { 120 throw new UnsupportedOperationException("FilterListIterator.add(Object) is not supported."); 121 } 122 123 @Override 124 public boolean hasNext() { 125 return nextObjectSet || setNextObject(); 126 } 127 128 @Override 129 public boolean hasPrevious() { 130 return previousObjectSet || setPreviousObject(); 131 } 132 133 @Override 134 public E next() { 135 if (!nextObjectSet && !setNextObject()) { 136 throw new NoSuchElementException(); 137 } 138 nextIndex++; 139 final E temp = nextObject; 140 clearNextObject(); 141 return temp; 142 } 143 144 @Override 145 public int nextIndex() { 146 return nextIndex; 147 } 148 149 @Override 150 public E previous() { 151 if (!previousObjectSet && !setPreviousObject()) { 152 throw new NoSuchElementException(); 153 } 154 nextIndex--; 155 final E temp = previousObject; 156 clearPreviousObject(); 157 return temp; 158 } 159 160 @Override 161 public int previousIndex() { 162 return nextIndex-1; 163 } 164 165 /** Not supported. */ 166 @Override 167 public void remove() { 168 throw new UnsupportedOperationException("FilterListIterator.remove() is not supported."); 169 } 170 171 /** 172 * Not supported. 173 * @param o the element with which to replace the last element returned by 174 * {@code next} or {@code previous} 175 */ 176 @Override 177 public void set(final E o) { 178 throw new UnsupportedOperationException("FilterListIterator.set(Object) is not supported."); 179 } 180 181 //----------------------------------------------------------------------- 182 /** 183 * Gets the iterator this iterator is using. 184 * 185 * @return the iterator. 186 */ 187 public ListIterator<? extends E> getListIterator() { 188 return iterator; 189 } 190 191 /** 192 * Sets the iterator for this iterator to use. 193 * If iteration has started, this effectively resets the iterator. 194 * 195 * @param iterator the iterator to use 196 */ 197 public void setListIterator(final ListIterator<? extends E> iterator) { 198 this.iterator = iterator; 199 } 200 201 //----------------------------------------------------------------------- 202 /** 203 * Gets the predicate this iterator is using. 204 * 205 * @return the predicate. 206 */ 207 public Predicate<? super E> getPredicate() { 208 return predicate; 209 } 210 211 /** 212 * Sets the predicate this the iterator to use. 213 * 214 * @param predicate the transformer to use 215 */ 216 public void setPredicate(final Predicate<? super E> predicate) { 217 this.predicate = predicate; 218 } 219 220 //----------------------------------------------------------------------- 221 private void clearNextObject() { 222 nextObject = null; 223 nextObjectSet = false; 224 } 225 226 private boolean setNextObject() { 227 // if previousObjectSet, 228 // then we've walked back one step in the 229 // underlying list (due to a hasPrevious() call) 230 // so skip ahead one matching object 231 if (previousObjectSet) { 232 clearPreviousObject(); 233 if (!setNextObject()) { 234 return false; 235 } 236 clearNextObject(); 237 } 238 239 if (iterator == null) { 240 return false; 241 } 242 while (iterator.hasNext()) { 243 final E object = iterator.next(); 244 if (predicate.evaluate(object)) { 245 nextObject = object; 246 nextObjectSet = true; 247 return true; 248 } 249 } 250 return false; 251 } 252 253 private void clearPreviousObject() { 254 previousObject = null; 255 previousObjectSet = false; 256 } 257 258 private boolean setPreviousObject() { 259 // if nextObjectSet, 260 // then we've walked back one step in the 261 // underlying list (due to a hasNext() call) 262 // so skip ahead one matching object 263 if (nextObjectSet) { 264 clearNextObject(); 265 if (!setPreviousObject()) { 266 return false; 267 } 268 clearPreviousObject(); 269 } 270 271 if (iterator == null) { 272 return false; 273 } 274 while (iterator.hasPrevious()) { 275 final E object = iterator.previous(); 276 if (predicate.evaluate(object)) { 277 previousObject = object; 278 previousObjectSet = true; 279 return true; 280 } 281 } 282 return false; 283 } 284 285}