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 (for example 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 }