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 * </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 * Not supported. 112 * @param o the element to insert 113 */ 114 @Override 115 public void add(final E o) { 116 throw new UnsupportedOperationException("FilterListIterator.add(Object) is not supported."); 117 } 118 119 private void clearNextObject() { 120 nextObject = null; 121 nextObjectSet = false; 122 } 123 124 private void clearPreviousObject() { 125 previousObject = null; 126 previousObjectSet = false; 127 } 128 129 /** 130 * Gets the iterator this iterator is using. 131 * 132 * @return the iterator. 133 */ 134 public ListIterator<? extends E> getListIterator() { 135 return iterator; 136 } 137 138 /** 139 * Gets the predicate this iterator is using. 140 * 141 * @return the predicate. 142 */ 143 public Predicate<? super E> getPredicate() { 144 return predicate; 145 } 146 147 @Override 148 public boolean hasNext() { 149 return nextObjectSet || setNextObject(); 150 } 151 152 @Override 153 public boolean hasPrevious() { 154 return previousObjectSet || setPreviousObject(); 155 } 156 157 @Override 158 public E next() { 159 if (!nextObjectSet && !setNextObject()) { 160 throw new NoSuchElementException(); 161 } 162 nextIndex++; 163 final E temp = nextObject; 164 clearNextObject(); 165 return temp; 166 } 167 168 @Override 169 public int nextIndex() { 170 return nextIndex; 171 } 172 173 @Override 174 public E previous() { 175 if (!previousObjectSet && !setPreviousObject()) { 176 throw new NoSuchElementException(); 177 } 178 nextIndex--; 179 final E temp = previousObject; 180 clearPreviousObject(); 181 return temp; 182 } 183 184 @Override 185 public int previousIndex() { 186 return nextIndex - 1; 187 } 188 189 /** Not supported. */ 190 @Override 191 public void remove() { 192 throw new UnsupportedOperationException("FilterListIterator.remove() is not supported."); 193 } 194 195 /** 196 * Not supported. 197 * @param ignored the element with which to replace the last element returned by 198 * {@code next} or {@code previous} 199 */ 200 @Override 201 public void set(final E ignored) { 202 throw new UnsupportedOperationException("FilterListIterator.set(Object) is not supported."); 203 } 204 205 /** 206 * Sets the iterator for this iterator to use. 207 * If iteration has started, this effectively resets the iterator. 208 * 209 * @param iterator the iterator to use 210 */ 211 public void setListIterator(final ListIterator<? extends E> iterator) { 212 this.iterator = iterator; 213 } 214 215 private boolean setNextObject() { 216 // if previousObjectSet, 217 // then we've walked back one step in the 218 // underlying list (due to a hasPrevious() call) 219 // so skip ahead one matching object 220 if (previousObjectSet) { 221 clearPreviousObject(); 222 if (!setNextObject()) { 223 return false; 224 } 225 clearNextObject(); 226 } 227 228 if (iterator == null) { 229 return false; 230 } 231 while (iterator.hasNext()) { 232 final E object = iterator.next(); 233 if (predicate.test(object)) { 234 nextObject = object; 235 nextObjectSet = true; 236 return true; 237 } 238 } 239 return false; 240 } 241 242 /** 243 * Sets the predicate this the iterator to use. 244 * 245 * @param predicate the transformer to use 246 */ 247 public void setPredicate(final Predicate<? super E> predicate) { 248 this.predicate = predicate; 249 } 250 251 private boolean setPreviousObject() { 252 // if nextObjectSet, 253 // then we've walked back one step in the 254 // underlying list (due to a hasNext() call) 255 // so skip ahead one matching object 256 if (nextObjectSet) { 257 clearNextObject(); 258 if (!setPreviousObject()) { 259 return false; 260 } 261 clearPreviousObject(); 262 } 263 264 if (iterator == null) { 265 return false; 266 } 267 while (iterator.hasPrevious()) { 268 final E object = iterator.previous(); 269 if (predicate.test(object)) { 270 previousObject = object; 271 previousObjectSet = true; 272 return true; 273 } 274 } 275 return false; 276 } 277 278}