FilterIterator.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.collections4.iterators;

  18. import java.util.Iterator;
  19. import java.util.NoSuchElementException;

  20. import org.apache.commons.collections4.Predicate;
  21. import org.apache.commons.collections4.functors.TruePredicate;

  22. /**
  23.  * Decorates an {@link Iterator} using an optional predicate to filter elements.
  24.  * <p>
  25.  * This iterator decorates the underlying iterator, only allowing through
  26.  * those elements that match the specified {@link Predicate Predicate}.
  27.  * </p>
  28.  *
  29.  * @param <E> the type of elements returned by this iterator.
  30.  * @since 1.0
  31.  */
  32. public class FilterIterator<E> implements IteratorOperations<E> {

  33.     /** The iterator to be filtered. */
  34.     private Iterator<? extends E> iterator;

  35.     /** The predicate to filter elements. */
  36.     private Predicate<? super E> predicate = TruePredicate.truePredicate();

  37.     /** The next object in the iteration. */
  38.     private E nextObject;

  39.     /** Whether the next object has been calculated yet. */
  40.     private boolean nextObjectSet;

  41.     /**
  42.      * Constructs a new {@code FilterIterator} that will not function
  43.      * until {@link #setIterator(Iterator) setIterator} is invoked.
  44.      */
  45.     public FilterIterator() {
  46.     }

  47.     /**
  48.      * Constructs a new {@code FilterIterator} that will not function
  49.      * until {@link #setPredicate(Predicate) setPredicate} is invoked.
  50.      *
  51.      * @param iterator  the iterator to use
  52.      */
  53.     public FilterIterator(final Iterator<? extends E> iterator) {
  54.         this.iterator = iterator;
  55.     }

  56.     /**
  57.      * Constructs a new {@code FilterIterator} that will use the
  58.      * given iterator and predicate.
  59.      *
  60.      * @param iterator  the iterator to use
  61.      * @param predicate  the predicate to use, null accepts all values.
  62.      */
  63.     public FilterIterator(final Iterator<? extends E> iterator, final Predicate<? super E> predicate) {
  64.         this.iterator = iterator;
  65.         this.predicate = safePredicate(predicate);
  66.     }

  67.     /**
  68.      * Gets the iterator this iterator is using.
  69.      *
  70.      * @return the underlying iterator.
  71.      */
  72.     public Iterator<? extends E> getIterator() {
  73.         return iterator;
  74.     }

  75.     /**
  76.      * Gets the predicate this iterator is using.
  77.      *
  78.      * @return the filtering predicate.
  79.      */
  80.     public Predicate<? super E> getPredicate() {
  81.         return predicate;
  82.     }

  83.     /**
  84.      * Returns true if the underlying iterator contains an object that
  85.      * matches the predicate.
  86.      *
  87.      * @return true if there is another object that matches the predicate
  88.      * @throws NullPointerException if either the iterator or predicate are null
  89.      */
  90.     @Override
  91.     public boolean hasNext() {
  92.         return nextObjectSet || setNextObject();
  93.     }

  94.     /**
  95.      * Returns the next object that matches the predicate.
  96.      *
  97.      * @return the next object which matches the given predicate
  98.      * @throws NullPointerException if either the iterator or predicate are null
  99.      * @throws NoSuchElementException if there are no more elements that
  100.      *  match the predicate
  101.      */
  102.     @Override
  103.     public E next() {
  104.         if (!nextObjectSet && !setNextObject()) {
  105.             throw new NoSuchElementException();
  106.         }
  107.         nextObjectSet = false;
  108.         return nextObject;
  109.     }

  110.     /**
  111.      * Removes from the underlying collection of the base iterator the last
  112.      * element returned by this iterator.
  113.      * This method can only be called
  114.      * if {@code next()} was called, but not after
  115.      * {@code hasNext()}, because the {@code hasNext()} call
  116.      * changes the base iterator.
  117.      *
  118.      * @throws IllegalStateException if {@code hasNext()} has already
  119.      *  been called.
  120.      */
  121.     @Override
  122.     public void remove() {
  123.         if (nextObjectSet) {
  124.             throw new IllegalStateException("remove() cannot be called");
  125.         }
  126.         iterator.remove();
  127.     }

  128.     private Predicate<? super E> safePredicate(final Predicate<? super E> predicate) {
  129.         return predicate != null ? predicate : TruePredicate.truePredicate();
  130.     }

  131.     /**
  132.      * Sets the iterator for this iterator to use.
  133.      * If iteration has started, this effectively resets the iterator.
  134.      *
  135.      * @param iterator  the iterator to use
  136.      */
  137.     public void setIterator(final Iterator<? extends E> iterator) {
  138.         this.iterator = iterator;
  139.         nextObject = null;
  140.         nextObjectSet = false;
  141.     }

  142.     /**
  143.      * Sets nextObject to the next object. If there are no more
  144.      * objects, then return false. Otherwise, return true.
  145.      */
  146.     private boolean setNextObject() {
  147.         while (iterator.hasNext()) {
  148.             final E object = iterator.next();
  149.             if (predicate.test(object)) {
  150.                 nextObject = object;
  151.                 nextObjectSet = true;
  152.                 return true;
  153.             }
  154.         }
  155.         return false;
  156.     }

  157.     /**
  158.      * Sets the predicate this the iterator to use where null accepts all values.
  159.      *
  160.      * @param predicate  the predicate to use, null accepts all values.
  161.      */
  162.     public void setPredicate(final Predicate<? super E> predicate) {
  163.         this.predicate = safePredicate(predicate);
  164.         nextObject = null;
  165.         nextObjectSet = false;
  166.     }

  167. }