1 /*
2 * Copyright 2016-2020 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.springframework.data.util;
17
18 import java.util.Arrays;
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.Set;
22 import java.util.function.BiConsumer;
23 import java.util.function.BinaryOperator;
24 import java.util.function.Function;
25 import java.util.function.Predicate;
26 import java.util.function.Supplier;
27 import java.util.stream.Collector;
28 import java.util.stream.Collectors;
29 import java.util.stream.Stream;
30 import java.util.stream.StreamSupport;
31
32 import org.springframework.util.Assert;
33
34 /**
35 * Simple interface to ease streamability of {@link Iterable}s.
36 *
37 * @author Oliver Gierke
38 * @author Christoph Strobl
39 * @since 2.0
40 */
41 @FunctionalInterface
42 public interface Streamable<T> extends Iterable<T>, Supplier<Stream<T>> {
43
44 /**
45 * Returns an empty {@link Streamable}.
46 *
47 * @return will never be {@literal null}.
48 */
49 static <T> Streamable<T> empty() {
50 return Collections::emptyIterator;
51 }
52
53 /**
54 * Returns a {@link Streamable} with the given elements.
55 *
56 * @param t the elements to return.
57 * @return
58 */
59 @SafeVarargs
60 static <T> Streamable<T> of(T... t) {
61 return () -> Arrays.asList(t).iterator();
62 }
63
64 /**
65 * Returns a {@link Streamable} for the given {@link Iterable}.
66 *
67 * @param iterable must not be {@literal null}.
68 * @return
69 */
70 static <T> Streamable<T> of(Iterable<T> iterable) {
71
72 Assert.notNull(iterable, "Iterable must not be null!");
73
74 return iterable::iterator;
75 }
76
77 static <T> Streamable<T> of(Supplier<? extends Stream<T>> supplier) {
78 return LazyStreamable.of(supplier);
79 }
80
81 /**
82 * Creates a non-parallel {@link Stream} of the underlying {@link Iterable}.
83 *
84 * @return will never be {@literal null}.
85 */
86 default Stream<T> stream() {
87 return StreamSupport.stream(spliterator(), false);
88 }
89
90 /**
91 * Returns a new {@link Streamable} that will apply the given {@link Function} to the current one.
92 *
93 * @param mapper must not be {@literal null}.
94 * @return
95 * @see Stream#map(Function)
96 */
97 default <R> Streamable<R> map(Function<? super T, ? extends R> mapper) {
98
99 Assert.notNull(mapper, "Mapping function must not be null!");
100
101 return Streamable.of(() -> stream().map(mapper));
102 }
103
104 /**
105 * Returns a new {@link Streamable} that will apply the given {@link Function} to the current one.
106 *
107 * @param mapper must not be {@literal null}.
108 * @return
109 * @see Stream#flatMap(Function)
110 */
111 default <R> Streamable<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper) {
112
113 Assert.notNull(mapper, "Mapping function must not be null!");
114
115 return Streamable.of(() -> stream().flatMap(mapper));
116 }
117
118 /**
119 * Returns a new {@link Streamable} that will apply the given filter {@link Predicate} to the current one.
120 *
121 * @param predicate must not be {@literal null}.
122 * @return
123 * @see Stream#filter(Predicate)
124 */
125 default Streamable<T> filter(Predicate<? super T> predicate) {
126
127 Assert.notNull(predicate, "Filter predicate must not be null!");
128
129 return Streamable.of(() -> stream().filter(predicate));
130 }
131
132 /**
133 * Returns whether the current {@link Streamable} is empty.
134 *
135 * @return
136 */
137 default boolean isEmpty() {
138 return !iterator().hasNext();
139 }
140
141 /**
142 * Creates a new {@link Streamable} from the current one and the given {@link Stream} concatenated.
143 *
144 * @param stream must not be {@literal null}.
145 * @return
146 * @since 2.1
147 */
148 default Streamable<T> and(Supplier<? extends Stream<? extends T>> stream) {
149
150 Assert.notNull(stream, "Stream must not be null!");
151
152 return Streamable.of(() -> Stream.concat(this.stream(), stream.get()));
153 }
154
155 /**
156 * Creates a new {@link Streamable} from the current one and the given values concatenated.
157 *
158 * @param others must not be {@literal null}.
159 * @return will never be {@literal null}.
160 * @since 2.2
161 */
162 @SuppressWarnings("unchecked")
163 default Streamable<T> and(T... others) {
164
165 Assert.notNull(others, "Other values must not be null!");
166
167 return Streamable.of(() -> Stream.concat(this.stream(), Arrays.stream(others)));
168 }
169
170 /**
171 * Creates a new {@link Streamable} from the current one and the given {@link Iterable} concatenated.
172 *
173 * @param iterable must not be {@literal null}.
174 * @return will never be {@literal null}.
175 * @since 2.2
176 */
177 default Streamable<T> and(Iterable<? extends T> iterable) {
178
179 Assert.notNull(iterable, "Iterable must not be null!");
180
181 return Streamable.of(() -> Stream.concat(this.stream(), StreamSupport.stream(iterable.spliterator(), false)));
182 }
183
184 /**
185 * Convenience method to allow adding a {@link Streamable} directly as otherwise the invocation is ambiguous between
186 * {@link #and(Iterable)} and {@link #and(Supplier)}.
187 *
188 * @param streamable must not be {@literal null}.
189 * @return will never be {@literal null}.
190 * @since 2.2
191 */
192 default Streamable<T> and(Streamable<? extends T> streamable) {
193 return and((Supplier<? extends Stream<? extends T>>) streamable);
194 }
195
196 /**
197 * Creates a new, unmodifiable {@link List}.
198 *
199 * @return will never be {@literal null}.
200 * @since 2.2
201 */
202 default List<T> toList() {
203 return stream().collect(StreamUtils.toUnmodifiableList());
204 }
205
206 /**
207 * Creates a new, unmodifiable {@link Set}.
208 *
209 * @return will never be {@literal null}.
210 * @since 2.2
211 */
212 default Set<T> toSet() {
213 return stream().collect(StreamUtils.toUnmodifiableSet());
214 }
215
216 /*
217 * (non-Javadoc)
218 * @see java.util.function.Supplier#get()
219 */
220 default Stream<T> get() {
221 return stream();
222 }
223
224 /**
225 * A collector to easily produce a {@link Streamable} from a {@link Stream} using {@link Collectors#toList} as
226 * intermediate collector.
227 *
228 * @return
229 * @see #toStreamable(Collector)
230 * @since 2.2
231 */
232 public static <S> Collector<S, ?, Streamable<S>> toStreamable() {
233 return toStreamable(Collectors.toList());
234 }
235
236 /**
237 * A collector to easily produce a {@link Streamable} from a {@link Stream} and the given intermediate collector.
238 *
239 * @return
240 * @since 2.2
241 */
242 @SuppressWarnings("unchecked")
243 public static <S, T extends Iterable<S>> Collector<S, ?, Streamable<S>> toStreamable(
244 Collector<S, ?, T> intermediate) {
245
246 return Collector.of( //
247 (Supplier<T>) intermediate.supplier(), //
248 (BiConsumer<T, S>) intermediate.accumulator(), //
249 (BinaryOperator<T>) intermediate.combiner(), //
250 Streamable::of);
251 }
252 }
253