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