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 */
017 package org.apache.commons.collections.iterators;
018
019 import java.util.List;
020 import java.util.ListIterator;
021
022 import org.apache.commons.collections.ResettableListIterator;
023
024 /**
025 * Iterates backwards through a List, starting with the last element
026 * and continuing to the first. This is useful for looping around
027 * a list in reverse order without needing to actually reverse the list.
028 * <p>
029 * The first call to <code>next()</code> will return the last element
030 * from the list, and so on. The <code>hasNext()</code> method works
031 * in concert with the <code>next()</code> method as expected.
032 * However, the <code>nextIndex()</code> method returns the correct
033 * index in the list, thus it starts high and reduces as the iteration
034 * continues. The previous methods work similarly.
035 *
036 * @author Serge Knystautas
037 * @author Stephen Colebourne
038 * @since Commons Collections 3.2
039 * @version $Revision: $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
040 */
041 public class ReverseListIterator implements ResettableListIterator {
042
043 /** The list being wrapped. */
044 private final List list;
045 /** The list iterator being wrapped. */
046 private ListIterator iterator;
047 /** Flag to indicate if updating is possible at the moment. */
048 private boolean validForUpdate = true;
049
050 /**
051 * Constructor that wraps a list.
052 *
053 * @param list the list to create a reversed iterator for
054 * @throws NullPointerException if the list is null
055 */
056 public ReverseListIterator(List list) {
057 super();
058 this.list = list;
059 iterator = list.listIterator(list.size());
060 }
061
062 //-----------------------------------------------------------------------
063 /**
064 * Checks whether there is another element.
065 *
066 * @return true if there is another element
067 */
068 public boolean hasNext() {
069 return iterator.hasPrevious();
070 }
071
072 /**
073 * Gets the next element.
074 * The next element is the previous in the list.
075 *
076 * @return the next element in the iterator
077 */
078 public Object next() {
079 Object obj = iterator.previous();
080 validForUpdate = true;
081 return obj;
082 }
083
084 /**
085 * Gets the index of the next element.
086 *
087 * @return the index of the next element in the iterator
088 */
089 public int nextIndex() {
090 return iterator.previousIndex();
091 }
092
093 /**
094 * Checks whether there is a previous element.
095 *
096 * @return true if there is a previous element
097 */
098 public boolean hasPrevious() {
099 return iterator.hasNext();
100 }
101
102 /**
103 * Gets the previous element.
104 * The next element is the previous in the list.
105 *
106 * @return the previous element in the iterator
107 */
108 public Object previous() {
109 Object obj = iterator.next();
110 validForUpdate = true;
111 return obj;
112 }
113
114 /**
115 * Gets the index of the previous element.
116 *
117 * @return the index of the previous element in the iterator
118 */
119 public int previousIndex() {
120 return iterator.nextIndex();
121 }
122
123 /**
124 * Removes the last returned element.
125 *
126 * @throws UnsupportedOperationException if the list is unmodifiable
127 * @throws IllegalStateException if there is no element to remove
128 */
129 public void remove() {
130 if (validForUpdate == false) {
131 throw new IllegalStateException("Cannot remove from list until next() or previous() called");
132 }
133 iterator.remove();
134 }
135
136 /**
137 * Replaces the last returned element.
138 *
139 * @param obj the object to set
140 * @throws UnsupportedOperationException if the list is unmodifiable
141 * @throws IllegalStateException if the iterator is not in a valid state for set
142 */
143 public void set(Object obj) {
144 if (validForUpdate == false) {
145 throw new IllegalStateException("Cannot set to list until next() or previous() called");
146 }
147 iterator.set(obj);
148 }
149
150 /**
151 * Adds a new element to the list between the next and previous elements.
152 *
153 * @param obj the object to add
154 * @throws UnsupportedOperationException if the list is unmodifiable
155 * @throws IllegalStateException if the iterator is not in a valid state for set
156 */
157 public void add(Object obj) {
158 // the validForUpdate flag is needed as the necessary previous()
159 // method call re-enables remove and add
160 if (validForUpdate == false) {
161 throw new IllegalStateException("Cannot add to list until next() or previous() called");
162 }
163 validForUpdate = false;
164 iterator.add(obj);
165 iterator.previous();
166 }
167
168 /**
169 * Resets the iterator back to the start (which is the
170 * end of the list as this is a reversed iterator)
171 */
172 public void reset() {
173 iterator = list.listIterator(list.size());
174 }
175
176 }