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