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 * @version $Id: FilterListIterator.html 972421 2015-11-14 20:00:04Z tn $ 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</code>). 050 */ 051 private boolean nextObjectSet = false; 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</code>). 062 */ 063 private boolean previousObjectSet = false; 064 065 /** 066 * The index of the element that would be returned by {@link #next}. 067 */ 068 private int nextIndex = 0; 069 070 //----------------------------------------------------------------------- 071 /** 072 * Constructs a new <code>FilterListIterator</code> that will not function 073 * until {@link #setListIterator(ListIterator) setListIterator} 074 * and {@link #setPredicate(Predicate) setPredicate} are invoked. 075 */ 076 public FilterListIterator() { 077 super(); 078 } 079 080 /** 081 * Constructs a new <code>FilterListIterator</code> that will not 082 * function until {@link #setPredicate(Predicate) setPredicate} is invoked. 083 * 084 * @param iterator the iterator to use 085 */ 086 public FilterListIterator(final ListIterator<? extends E> iterator ) { 087 super(); 088 this.iterator = iterator; 089 } 090 091 /** 092 * Constructs a new <code>FilterListIterator</code>. 093 * 094 * @param iterator the iterator to use 095 * @param predicate the predicate to use 096 */ 097 public FilterListIterator(final ListIterator<? extends E> iterator, final Predicate<? super E> predicate) { 098 super(); 099 this.iterator = iterator; 100 this.predicate = predicate; 101 } 102 103 /** 104 * Constructs a new <code>FilterListIterator</code> that will not function 105 * until {@link #setListIterator(ListIterator) setListIterator} is invoked. 106 * 107 * @param predicate the predicate to use. 108 */ 109 public FilterListIterator(final Predicate<? super E> predicate) { 110 super(); 111 this.predicate = predicate; 112 } 113 114 //----------------------------------------------------------------------- 115 /** Not supported. */ 116 public void add(final E o) { 117 throw new UnsupportedOperationException("FilterListIterator.add(Object) is not supported."); 118 } 119 120 public boolean hasNext() { 121 return nextObjectSet || setNextObject(); 122 } 123 124 public boolean hasPrevious() { 125 return previousObjectSet || setPreviousObject(); 126 } 127 128 public E next() { 129 if (!nextObjectSet) { 130 if (!setNextObject()) { 131 throw new NoSuchElementException(); 132 } 133 } 134 nextIndex++; 135 final E temp = nextObject; 136 clearNextObject(); 137 return temp; 138 } 139 140 public int nextIndex() { 141 return nextIndex; 142 } 143 144 public E previous() { 145 if (!previousObjectSet) { 146 if (!setPreviousObject()) { 147 throw new NoSuchElementException(); 148 } 149 } 150 nextIndex--; 151 final E temp = previousObject; 152 clearPreviousObject(); 153 return temp; 154 } 155 156 public int previousIndex() { 157 return nextIndex-1; 158 } 159 160 /** Not supported. */ 161 public void remove() { 162 throw new UnsupportedOperationException("FilterListIterator.remove() is not supported."); 163 } 164 165 /** Not supported. */ 166 public void set(final E o) { 167 throw new UnsupportedOperationException("FilterListIterator.set(Object) is not supported."); 168 } 169 170 //----------------------------------------------------------------------- 171 /** 172 * Gets the iterator this iterator is using. 173 * 174 * @return the iterator. 175 */ 176 public ListIterator<? extends E> getListIterator() { 177 return iterator; 178 } 179 180 /** 181 * Sets the iterator for this iterator to use. 182 * If iteration has started, this effectively resets the iterator. 183 * 184 * @param iterator the iterator to use 185 */ 186 public void setListIterator(final ListIterator<? extends E> iterator) { 187 this.iterator = iterator; 188 } 189 190 //----------------------------------------------------------------------- 191 /** 192 * Gets the predicate this iterator is using. 193 * 194 * @return the predicate. 195 */ 196 public Predicate<? super E> getPredicate() { 197 return predicate; 198 } 199 200 /** 201 * Sets the predicate this the iterator to use. 202 * 203 * @param predicate the transformer to use 204 */ 205 public void setPredicate(final Predicate<? super E> predicate) { 206 this.predicate = predicate; 207 } 208 209 //----------------------------------------------------------------------- 210 private void clearNextObject() { 211 nextObject = null; 212 nextObjectSet = false; 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.evaluate(object)) { 234 nextObject = object; 235 nextObjectSet = true; 236 return true; 237 } 238 } 239 return false; 240 } 241 242 private void clearPreviousObject() { 243 previousObject = null; 244 previousObjectSet = false; 245 } 246 247 private boolean setPreviousObject() { 248 // if nextObjectSet, 249 // then we've walked back one step in the 250 // underlying list (due to a hasNext() call) 251 // so skip ahead one matching object 252 if (nextObjectSet) { 253 clearNextObject(); 254 if (!setPreviousObject()) { 255 return false; 256 } 257 clearPreviousObject(); 258 } 259 260 if (iterator == null) { 261 return false; 262 } 263 while (iterator.hasPrevious()) { 264 final E object = iterator.previous(); 265 if (predicate.evaluate(object)) { 266 previousObject = object; 267 previousObjectSet = true; 268 return true; 269 } 270 } 271 return false; 272 } 273 274}