1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package org.apache.commons.collections4.iterators; 18 19 import java.util.Collections; 20 import java.util.Iterator; 21 import java.util.function.Consumer; 22 import java.util.function.Function; 23 import java.util.function.Predicate; 24 import java.util.stream.Stream; 25 26 import org.apache.commons.collections4.IteratorUtils; 27 28 /** 29 * Extends Iterator functionality to include operations commonly found on streams (e.g. filtering, concatenating, mapping). It also provides convenience methods 30 * for common operations. 31 * 32 * @param <T> The type of object returned from the iterator. 33 * @since 4.5.0-M3 34 */ 35 public final class ExtendedIterator<T> implements IteratorOperations<T> { 36 37 /** 38 * Create an ExtendedIterator returning the elements of <code>it</code>. If <code>it</code> is itself an ExtendedIterator, return that; otherwise wrap 39 * <code>it</code>. 40 * 41 * @param <T> The type of object returned from the iterator. 42 * @param it The iterator to wrap. 43 * @return An Extended iterator wrapping {@code it} 44 */ 45 public static <T> ExtendedIterator<T> create(final Iterator<T> it) { 46 return it instanceof ExtendedIterator<?> ? (ExtendedIterator<T>) it : new ExtendedIterator<>(it, false); 47 } 48 49 /** 50 * Creates an ExtendedIterator wrapped round a {@link Stream}. The extended iterator does not permit <code>.remove()</code>. 51 * <p> 52 * The stream should not be used directly. The effect of doing so is undefined. 53 * </p> 54 * 55 * @param <T> The type of object returned from the iterator. 56 * @param stream the Stream to create an iterator from. 57 * @return an Extended iterator on the {@code stream} iterator. 58 */ 59 public static <T> ExtendedIterator<T> create(final Stream<T> stream) { 60 return new ExtendedIterator<>(stream.iterator(), true); 61 } 62 63 /** 64 * Creates an ExtendedIterator wrapped round <code>it</code>, which does not permit <code>.remove()</code> even if <code>it</code> does. 65 * 66 * @param <T> The type of object returned from the iterator. 67 * @param it The Iterator to wrap. 68 * @return an Extended iterator on {@code it} 69 * @throws UnsupportedOperationException if remove() is called on the resulting iterator. 70 */ 71 public static <T> ExtendedIterator<T> createNoRemove(final Iterator<T> it) { 72 return new ExtendedIterator<>(it, true); 73 } 74 75 /** 76 * Creates an empty Extended iterator. 77 * 78 * @return An empty Extended iterator. 79 */ 80 public static ExtendedIterator<?> emptyIterator() { 81 return new ExtendedIterator<>(Collections.emptyIterator(), false); 82 } 83 84 /** 85 * Flattens an iterator of iterators into an Iterator over the next level values. Similar to list splicing in lisp. 86 * 87 * @param <T> The type of object returned from the iterator. 88 * @param iterators An iterator of iterators. 89 * @return An iterator over the logical concatenation of the inner iterators. 90 */ 91 public static <T> ExtendedIterator<T> flatten(final Iterator<Iterator<T>> iterators) { 92 return create(IteratorUtils.chainedIterator(iterators)); 93 } 94 95 /** 96 * Set to <code>true</code> if this wrapping doesn't permit the use of {@link #remove()}, otherwise removal is delegated to the base iterator. 97 */ 98 private final boolean throwOnRemove; 99 100 /** The base iterator that we wrap */ 101 private final Iterator<? extends T> base; 102 103 /** 104 * Initialize this wrapping with the given base iterator and remove-control. 105 * 106 * @param base the base iterator that this iterator wraps 107 * @param throwOnRemove true if .remove() must throw an exception 108 */ 109 private ExtendedIterator(final Iterator<? extends T> base, final boolean throwOnRemove) { 110 this.base = base; 111 this.throwOnRemove = throwOnRemove; 112 } 113 114 /** 115 * Chains the {@code other} iterator to the end of this one. 116 * 117 * @param other the other iterator to extend this iterator with. 118 * @return A new iterator returning the contents of {@code this} iterator followed by the contents of {@code other} iterator. 119 * @param <X> The type of object returned from the other iterator. 120 */ 121 public <X extends T> ExtendedIterator<T> andThen(final Iterator<X> other) { 122 if (base instanceof IteratorChain) { 123 ((IteratorChain<T>) base).addIterator(other); 124 return this; 125 } 126 return new ExtendedIterator<>(new IteratorChain<>(base, other), throwOnRemove); 127 } 128 129 /** 130 * Filter this iterator using a predicate. Only items for which the predicate returns {@code true} will be included in the result. 131 * 132 * @param predicate The predicate to filter the items with. 133 * @return An iterator filtered by the predicate. 134 */ 135 public ExtendedIterator<T> filter(final Predicate<T> predicate) { 136 return new ExtendedIterator<>(new FilterIterator<>(this, predicate::test), throwOnRemove); 137 } 138 139 @Override 140 public void forEachRemaining(final Consumer<? super T> action) { 141 base.forEachRemaining(action); 142 } 143 144 @Override 145 public boolean hasNext() { 146 return base.hasNext(); 147 } 148 149 /** 150 * Map the elements of the iterator to a now type. 151 * 152 * @param function The function to map elements of {@code <T>} to type {@code <U>}. 153 * @return An Extended iterator that returns a {@code <U>} for very {@code <T>} in the original iterator. 154 * @param <U> The object type to return. 155 */ 156 public <U> ExtendedIterator<U> map(final Function<T, U> function) { 157 return new ExtendedIterator<>(new TransformIterator<>(this, function::apply), false); 158 } 159 160 @Override 161 public T next() { 162 return base.next(); 163 } 164 165 @Override 166 public void remove() { 167 if (throwOnRemove) { 168 throw new UnsupportedOperationException(); 169 } 170 base.remove(); 171 } 172 }