001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.commons.collections4.iterators; 019 020import java.util.Iterator; 021 022import org.apache.commons.collections4.ArrayStack; 023 024/** 025 * Decorates an iterator to support pushback of elements. 026 * <p> 027 * The decorator stores the pushed back elements in a LIFO manner: the last element 028 * that has been pushed back, will be returned as the next element in a call to {@link #next()}. 029 * <p> 030 * The decorator does not support the removal operation. Any call to {@link #remove()} will 031 * result in an {@link UnsupportedOperationException}. 032 * 033 * @since 4.0 034 * @version $Id: PushbackIterator.html 972421 2015-11-14 20:00:04Z tn $ 035 */ 036@SuppressWarnings("deprecation") // replace ArrayStack with ArrayDeque when moving to Java 6 037public class PushbackIterator<E> implements Iterator<E> { 038 039 /** The iterator being decorated. */ 040 private final Iterator<? extends E> iterator; 041 042 /** The LIFO queue containing the pushed back items. */ 043 private ArrayStack<E> items = new ArrayStack<E>(); 044 045 //----------------------------------------------------------------------- 046 /** 047 * Decorates the specified iterator to support one-element lookahead. 048 * <p> 049 * If the iterator is already a {@link PeekingIterator} it is returned directly. 050 * 051 * @param <E> the element type 052 * @param iterator the iterator to decorate 053 * @return a new peeking iterator 054 * @throws IllegalArgumentException if the iterator is null 055 */ 056 public static <E> PushbackIterator<E> pushbackIterator(final Iterator<? extends E> iterator) { 057 if (iterator == null) { 058 throw new IllegalArgumentException("Iterator must not be null"); 059 } 060 if (iterator instanceof PushbackIterator<?>) { 061 @SuppressWarnings("unchecked") // safe cast 062 final PushbackIterator<E> it = (PushbackIterator<E>) iterator; 063 return it; 064 } 065 return new PushbackIterator<E>(iterator); 066 } 067 068 //----------------------------------------------------------------------- 069 070 /** 071 * Constructor. 072 * 073 * @param iterator the iterator to decorate 074 */ 075 public PushbackIterator(final Iterator<? extends E> iterator) { 076 super(); 077 this.iterator = iterator; 078 } 079 080 /** 081 * Push back the given element to the iterator. 082 * <p> 083 * Calling {@link #next()} immediately afterwards will return exactly this element. 084 * 085 * @param item the element to push back to the iterator 086 */ 087 public void pushback(final E item) { 088 items.push(item); 089 } 090 091 public boolean hasNext() { 092 return !items.isEmpty() ? true : iterator.hasNext(); 093 } 094 095 public E next() { 096 return !items.isEmpty() ? items.pop() : iterator.next(); 097 } 098 099 /** 100 * This iterator will always throw an {@link UnsupportedOperationException}. 101 * 102 * @throws UnsupportedOperationException always 103 */ 104 public void remove() { 105 throw new UnsupportedOperationException(); 106 } 107 108}