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