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