/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.lang3.stream; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Set; import java.util.Spliterator; import java.util.Spliterators; import java.util.Spliterators.AbstractSpliterator; import java.util.function.BiConsumer; import java.util.function.BinaryOperator; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; import java.util.function.Supplier; import java.util.stream.Collector; import java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.StreamSupport; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.function.Failable; import org.apache.commons.lang3.function.FailableConsumer; import org.apache.commons.lang3.function.FailableFunction; import org.apache.commons.lang3.function.FailablePredicate; /** * Provides utility functions, and classes for working with the {@code java.util.stream} package, or more generally, * with Java 8 lambdas. More specifically, it attempts to address the fact that lambdas are supposed not to throw * Exceptions, at least not checked Exceptions, AKA instances of {@link Exception}. This enforces the use of constructs * like: * *
* {@code * Consumer*consumer = m -> { * try { * m.invoke(o, args); * } catch (Throwable t) { * throw Failable.rethrow(t); * } * }; * stream.forEach(consumer); * } *
* Using a {@link FailableStream}, this can be rewritten as follows: *
* ** {@code * Streams.failable(stream).forEach((m) -> m.invoke(o, args)); * } ** * Obviously, the second version is much more concise and the spirit of Lambda expressions is met better than in the * first version. * * @see Stream * @see Failable * @since 3.11 */ public class Streams { /** * A Collector type for arrays. * * @param
* This is a short-circuiting terminal operation. *
* * Note This method evaluates the universal quantification of the predicate over the elements of the stream * (for all x P(x)). If the stream is empty, the quantification is said to be vacuously satisfied and is always * {@code true} (regardless of P(x)). * * @param predicate A non-interfering, stateless predicate to apply to elements of this stream * @return {@code true} If either all elements of the stream match the provided predicate or the stream is empty, * otherwise {@code false}. */ public boolean allMatch(final FailablePredicate* This is a short-circuiting terminal operation. *
* * Note This method evaluates the existential quantification of the predicate over the elements of the stream * (for some x P(x)). * * @param predicate A non-interfering, stateless predicate to apply to elements of this stream * @return {@code true} if any elements of the stream match the provided predicate, otherwise {@code false} */ public boolean anyMatch(final FailablePredicate* If the underlying stream is parallel, and the {@link Collector} is concurrent, and either the stream is unordered or * the collector is unordered, then a concurrent reduction will be performed (see {@link Collector} for details on * concurrent reduction.) *
* ** This is a terminal operation. *
* ** When executed in parallel, multiple intermediate results may be instantiated, populated, and merged so as to maintain * isolation of mutable data structures. Therefore, even when executed in parallel with non-thread-safe data structures * (such as {@link ArrayList}), no additional synchronization is needed for a parallel reduction. *
* * Note The following will accumulate strings into an ArrayList: * ** {@code * List* *asList = stringStream.collect(Collectors.toList()); * } *
* The following will classify {@code Person} objects by city: *
* ** {@code * Map* *> peopleByCity = personStream.collect(Collectors.groupingBy(Person::getCity)); * } *
* The following will classify {@code Person} objects by state and city, cascading two {@link Collector}s together: *
* ** {@code * Map* * @param>> peopleByStateAndCity = personStream * .collect(Collectors.groupingBy(Person::getState, Collectors.groupingBy(Person::getCity))); * } *
* {@code * R result = supplier.get(); * for (T element : this stream) * accumulator.accept(result, element); * return result; * } ** *
* Like {@link #reduce(Object, BinaryOperator)}, {@code collect} operations can be parallelized without requiring * additional synchronization. *
* ** This is a terminal operation. *
* * Note There are many existing classes in the JDK whose signatures are well-suited for use with method references as * arguments to {@code collect()}. For example, the following will accumulate strings into an {@link ArrayList}: * ** {@code * List* *asList = stringStream.collect(ArrayList::new, ArrayList::add, ArrayList::addAll); * } *
* The following will take a stream of strings and concatenates them into a single string: *
* ** {@code * String concat = stringStream.collect(StringBuilder::new, StringBuilder::append, StringBuilder::append).toString(); * } ** * @param
* This is an intermediate operation. *
* * @param predicate a non-interfering, stateless predicate to apply to each element to determine if it should be * included. * @return the new stream */ public FailableStream* This is a terminal operation. *
* ** The behavior of this operation is explicitly nondeterministic. For parallel stream pipelines, this operation does * not guarantee to respect the encounter order of the stream, as doing so would sacrifice the benefit of * parallelism. For any given element, the action may be performed at whatever time and in whatever thread the library * chooses. If the action accesses shared state, it is responsible for providing the required synchronization. *
* * @param action a non-interfering action to perform on the elements */ public void forEach(final FailableConsumer* This is an intermediate operation. *
* * @param* {@code * T result = identity; * for (T element : this stream) * result = accumulator.apply(result, element) * return result; * } ** * but is not constrained to execute sequentially. * *
* The {@code identity} value must be an identity for the accumulator function. This means that for all {@code t}, * {@code accumulator.apply(identity, t)} is equal to {@code t}. The {@code accumulator} function must be an associative * function. *
* ** This is a terminal operation. *
* * Note Sum, min, max, average, and string concatenation are all special cases of reduction. Summing a stream of numbers * can be expressed as: * ** {@code * Integer sum = integers.reduce(0, (a, b) -> a + b); * } ** * or: * *
* {@code * Integer sum = integers.reduce(0, Integer::sum); * } ** *
* While this may seem a more roundabout way to perform an aggregation compared to simply mutating a running total in a * loop, reduction operations parallelize more gracefully, without needing additional synchronization and with greatly * reduced risk of data races. *
* * @param identity the identity value for the accumulating function * @param accumulator an associative, non-interfering, stateless function for combining two values * @return the result of the reduction */ public T reduce(final T identity, final BinaryOperator* {@code * final List* * as follows: * *list; * final Method m; * final Function mapper = (o) -> { * try { * return (String) m.invoke(o); * } catch (Throwable t) { * throw Failable.rethrow(t); * } * }; * final List strList = list.stream().map(mapper).collect(Collectors.toList()); * } *
* {@code * final List* * While the second version may not be quite as efficient (because it depends on the creation of additional, * intermediate objects, of type FailableStream), it is much more concise, and readable, and meets the spirit of Lambdas * better than the first version. * * @paramlist; * final Method m; * final List strList = Failable.stream(list.stream()).map((o) -> (String) m.invoke(o)).collect(Collectors.toList()); * } *
* {@code * final List* * as follows: * *list; * final Method m; * final Function mapper = (o) -> { * try { * return (String) m.invoke(o); * } catch (Throwable t) { * throw Failable.rethrow(t); * } * }; * final List strList = list.stream().map(mapper).collect(Collectors.toList()); * } *
* {@code * final List* * While the second version may not be quite as efficient (because it depends on the creation of additional, * intermediate objects, of type FailableStream), it is much more concise, and readable, and meets the spirit of Lambdas * better than the first version. * * @paramlist; * final Method m; * final List strList = Failable.stream(list.stream()).map((o) -> (String) m.invoke(o)).collect(Collectors.toList()); * } *
* This method shorthand for: *
** {@code (Stream* * @param) Streams.toStream(collection).filter(collection, SomeClass.class::isInstance);} *
* {@code * final List* * as follows: * *list; * final Method m; * final Function mapper = (o) -> { * try { * return (String) m.invoke(o); * } catch (Throwable t) { * throw Failable.rethrow(t); * } * }; * final List strList = list.stream().map(mapper).collect(Collectors.toList()); * } *
* {@code * final List* * While the second version may not be quite as efficient (because it depends on the creation of additional, * intermediate objects, of type FailableStream), it is much more concise, and readable, and meets the spirit of Lambdas * better than the first version. * * @paramlist; * final Method m; * final List strList = Failable.stream(list.stream()).map((o) -> (String) m.invoke(o)).collect(Collectors.toList()); * } *
* {@code * final List* * as follows: * *list; * final Method m; * final Function mapper = (o) -> { * try { * return (String) m.invoke(o); * } catch (Throwable t) { * throw Failable.rethrow(t); * } * }; * final List strList = list.stream().map(mapper).collect(Collectors.toList()); * } *
* {@code * final List* * While the second version may not be quite as efficient (because it depends on the creation of additional, * intermediate objects, of type FailableStream), it is much more concise, and readable, and meets the spirit of Lambdas * better than the first version. * * @paramlist; * final Method m; * final List strList = Failable.stream(list.stream()).map((o) -> (String) m.invoke(o)).collect(Collectors.toList()); * } *