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 * https://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 046 /** The list iterator being wrapped. */ 047 private ListIterator<E> iterator; 048 049 /** Flag to indicate if updating is possible at the moment. */ 050 private boolean validForUpdate = true; 051 052 /** 053 * Constructor that wraps a list. 054 * 055 * @param list The list to create a reversed iterator for 056 * @throws NullPointerException if the list is null 057 */ 058 public ReverseListIterator(final List<E> list) { 059 this.list = Objects.requireNonNull(list, "list"); 060 iterator = list.listIterator(list.size()); 061 } 062 063 /** 064 * Adds a new element to the list between the next and previous elements. 065 * 066 * @param obj The object to add 067 * @throws UnsupportedOperationException if the list is unmodifiable 068 * @throws IllegalStateException if the iterator is not in a valid state for set 069 */ 070 @Override 071 public void add(final E obj) { 072 // the validForUpdate flag is needed as the necessary previous() 073 // method call re-enables remove and add 074 if (!validForUpdate) { 075 throw new IllegalStateException("Cannot add to list until next() or previous() called"); 076 } 077 validForUpdate = false; 078 iterator.add(obj); 079 iterator.previous(); 080 } 081 082 /** 083 * Checks whether there is another element. 084 * 085 * @return true if there is another element 086 */ 087 @Override 088 public boolean hasNext() { 089 return iterator.hasPrevious(); 090 } 091 092 /** 093 * Checks whether there is a previous element. 094 * 095 * @return true if there is a previous element 096 */ 097 @Override 098 public boolean hasPrevious() { 099 return iterator.hasNext(); 100 } 101 102 /** 103 * Gets the next element. 104 * The next element is the previous in the list. 105 * 106 * @return The next element in the iterator 107 */ 108 @Override 109 public E next() { 110 final E obj = iterator.previous(); 111 validForUpdate = true; 112 return obj; 113 } 114 115 /** 116 * Gets the index of the next element. 117 * 118 * @return The index of the next element in the iterator 119 */ 120 @Override 121 public int nextIndex() { 122 return iterator.previousIndex(); 123 } 124 125 /** 126 * Gets the previous element. 127 * The next element is the previous in the list. 128 * 129 * @return The previous element in the iterator 130 */ 131 @Override 132 public E previous() { 133 final E obj = iterator.next(); 134 validForUpdate = true; 135 return obj; 136 } 137 138 /** 139 * Gets the index of the previous element. 140 * 141 * @return The index of the previous element in the iterator 142 */ 143 @Override 144 public int previousIndex() { 145 return iterator.nextIndex(); 146 } 147 148 /** 149 * Removes the last returned element. 150 * 151 * @throws UnsupportedOperationException if the list is unmodifiable 152 * @throws IllegalStateException if there is no element to remove 153 */ 154 @Override 155 public void remove() { 156 if (!validForUpdate) { 157 throw new IllegalStateException("Cannot remove from list until next() or previous() called"); 158 } 159 iterator.remove(); 160 } 161 162 /** 163 * Resets the iterator back to the start (which is the 164 * end of the list as this is a reversed iterator) 165 */ 166 @Override 167 public void reset() { 168 iterator = list.listIterator(list.size()); 169 } 170 171 /** 172 * Replaces the last returned element. 173 * 174 * @param obj The object to set 175 * @throws UnsupportedOperationException if the list is unmodifiable 176 * @throws IllegalStateException if the iterator is not in a valid state for set 177 */ 178 @Override 179 public void set(final E obj) { 180 if (!validForUpdate) { 181 throw new IllegalStateException("Cannot set to list until next() or previous() called"); 182 } 183 iterator.set(obj); 184 } 185 186}