FilterListIterator.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.ListIterator;
  19. import java.util.NoSuchElementException;

  20. import org.apache.commons.collections4.Predicate;

  21. /**
  22.  * Decorates another {@link ListIterator} using a predicate to filter elements.
  23.  * <p>
  24.  * This iterator decorates the underlying iterator, only allowing through
  25.  * those elements that match the specified {@link Predicate Predicate}.
  26.  * </p>
  27.  *
  28.  * @param <E> the type of elements returned by this iterator.
  29.  * @since 2.0
  30.  */
  31. public class FilterListIterator<E> implements ListIterator<E> {

  32.     /** The iterator being used */
  33.     private ListIterator<? extends E> iterator;

  34.     /** The predicate being used */
  35.     private Predicate<? super E> predicate;

  36.     /**
  37.      * The value of the next (matching) object, when
  38.      * {@link #nextObjectSet} is true.
  39.      */
  40.     private E nextObject;

  41.     /**
  42.      * Whether or not the {@link #nextObject} has been set
  43.      * (possibly to {@code null}).
  44.      */
  45.     private boolean nextObjectSet;

  46.     /**
  47.      * The value of the previous (matching) object, when
  48.      * {@link #previousObjectSet} is true.
  49.      */
  50.     private E previousObject;

  51.     /**
  52.      * Whether or not the {@link #previousObject} has been set
  53.      * (possibly to {@code null}).
  54.      */
  55.     private boolean previousObjectSet;

  56.     /**
  57.      * The index of the element that would be returned by {@link #next}.
  58.      */
  59.     private int nextIndex;

  60.     /**
  61.      * Constructs a new {@code FilterListIterator} that will not function
  62.      * until {@link #setListIterator(ListIterator) setListIterator}
  63.      * and {@link #setPredicate(Predicate) setPredicate} are invoked.
  64.      */
  65.     public FilterListIterator() {
  66.     }

  67.     /**
  68.      * Constructs a new {@code FilterListIterator} that will not
  69.      * function until {@link #setPredicate(Predicate) setPredicate} is invoked.
  70.      *
  71.      * @param iterator  the iterator to use
  72.      */
  73.     public FilterListIterator(final ListIterator<? extends E> iterator) {
  74.         this.iterator = iterator;
  75.     }

  76.     /**
  77.      * Constructs a new {@code FilterListIterator}.
  78.      *
  79.      * @param iterator  the iterator to use
  80.      * @param predicate  the predicate to use
  81.      */
  82.     public FilterListIterator(final ListIterator<? extends E> iterator, final Predicate<? super E> predicate) {
  83.         this.iterator = iterator;
  84.         this.predicate = predicate;
  85.     }

  86.     /**
  87.      * Constructs a new {@code FilterListIterator} that will not function
  88.      * until {@link #setListIterator(ListIterator) setListIterator} is invoked.
  89.      *
  90.      * @param predicate  the predicate to use.
  91.      */
  92.     public FilterListIterator(final Predicate<? super E> predicate) {
  93.         this.predicate = predicate;
  94.     }

  95.     /**
  96.      * Not supported.
  97.      * @param o the element to insert
  98.      */
  99.     @Override
  100.     public void add(final E o) {
  101.         throw new UnsupportedOperationException("FilterListIterator.add(Object) is not supported.");
  102.     }

  103.     private void clearNextObject() {
  104.         nextObject = null;
  105.         nextObjectSet = false;
  106.     }

  107.     private void clearPreviousObject() {
  108.         previousObject = null;
  109.         previousObjectSet = false;
  110.     }

  111.     /**
  112.      * Gets the iterator this iterator is using.
  113.      *
  114.      * @return the iterator.
  115.      */
  116.     public ListIterator<? extends E> getListIterator() {
  117.         return iterator;
  118.     }

  119.     /**
  120.      * Gets the predicate this iterator is using.
  121.      *
  122.      * @return the predicate.
  123.      */
  124.     public Predicate<? super E> getPredicate() {
  125.         return predicate;
  126.     }

  127.     @Override
  128.     public boolean hasNext() {
  129.         return nextObjectSet || setNextObject();
  130.     }

  131.     @Override
  132.     public boolean hasPrevious() {
  133.         return previousObjectSet || setPreviousObject();
  134.     }

  135.     @Override
  136.     public E next() {
  137.         if (!nextObjectSet && !setNextObject()) {
  138.             throw new NoSuchElementException();
  139.         }
  140.         nextIndex++;
  141.         final E temp = nextObject;
  142.         clearNextObject();
  143.         return temp;
  144.     }

  145.     @Override
  146.     public int nextIndex() {
  147.         return nextIndex;
  148.     }

  149.     @Override
  150.     public E previous() {
  151.         if (!previousObjectSet && !setPreviousObject()) {
  152.             throw new NoSuchElementException();
  153.         }
  154.         nextIndex--;
  155.         final E temp = previousObject;
  156.         clearPreviousObject();
  157.         return temp;
  158.     }

  159.     @Override
  160.     public int previousIndex() {
  161.         return nextIndex - 1;
  162.     }

  163.     /** Not supported. */
  164.     @Override
  165.     public void remove() {
  166.         throw new UnsupportedOperationException("FilterListIterator.remove() is not supported.");
  167.     }

  168.     /**
  169.      * Not supported.
  170.      * @param ignored the element with which to replace the last element returned by
  171.      *          {@code next} or {@code previous}
  172.      */
  173.     @Override
  174.     public void set(final E ignored) {
  175.         throw new UnsupportedOperationException("FilterListIterator.set(Object) is not supported.");
  176.     }

  177.     /**
  178.      * Sets the iterator for this iterator to use.
  179.      * If iteration has started, this effectively resets the iterator.
  180.      *
  181.      * @param iterator  the iterator to use
  182.      */
  183.     public void setListIterator(final ListIterator<? extends E> iterator) {
  184.         this.iterator = iterator;
  185.     }

  186.     private boolean setNextObject() {
  187.         // if previousObjectSet,
  188.         // then we've walked back one step in the
  189.         // underlying list (due to a hasPrevious() call)
  190.         // so skip ahead one matching object
  191.         if (previousObjectSet) {
  192.             clearPreviousObject();
  193.             if (!setNextObject()) {
  194.                 return false;
  195.             }
  196.             clearNextObject();
  197.         }

  198.         if (iterator == null) {
  199.             return false;
  200.         }
  201.         while (iterator.hasNext()) {
  202.             final E object = iterator.next();
  203.             if (predicate.test(object)) {
  204.                 nextObject = object;
  205.                 nextObjectSet = true;
  206.                 return true;
  207.             }
  208.         }
  209.         return false;
  210.     }

  211.     /**
  212.      * Sets the predicate this the iterator to use.
  213.      *
  214.      * @param predicate  the transformer to use
  215.      */
  216.     public void setPredicate(final Predicate<? super E> predicate) {
  217.         this.predicate = predicate;
  218.     }

  219.     private boolean setPreviousObject() {
  220.         // if nextObjectSet,
  221.         // then we've walked back one step in the
  222.         // underlying list (due to a hasNext() call)
  223.         // so skip ahead one matching object
  224.         if (nextObjectSet) {
  225.             clearNextObject();
  226.             if (!setPreviousObject()) {
  227.                 return false;
  228.             }
  229.             clearPreviousObject();
  230.         }

  231.         if (iterator == null) {
  232.             return false;
  233.         }
  234.         while (iterator.hasPrevious()) {
  235.             final E object = iterator.previous();
  236.             if (predicate.test(object)) {
  237.                 previousObject = object;
  238.                 previousObjectSet = true;
  239.                 return true;
  240.             }
  241.         }
  242.         return false;
  243.     }

  244. }