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 }