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