All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.paumard.streams.StreamsUtils Maven / Gradle / Ivy

Go to download

Streams Utils is a set of operations written on Java 8 Streams. It allows several basic operations that are not available in the the Java 8, and that have proven to be very useful in some cases.

There is a newer version: 2.1.1
Show newest version
/*
 * Copyright (C) 2015 José Paumard
 *
 * Licensed 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.paumard.streams;

import org.paumard.spliterators.*;

import java.util.*;
import java.util.function.*;
import java.util.stream.*;

import static java.util.function.Function.identity;

/**
 * 

A factory class used to create streams from other streams. There are currently seven ways of rearranging streams. *

*

Here is a first example of what can be done:

*
{@code
 *     // Create an example Stream
 *     Stream stream = Stream.of("a0", "a1", "a2", "a3");
 *     Stream> groupingStream = StreamsUtils.group(stream, 2);
 *     List> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList());
 *     // The collect list is [["a0", "a1"]["a2", "a3"]]
 * }
*

See the documentation of each factory method for more information.

* * @author José Paumard * @since 0.1 */ public class StreamsUtils { /** *

Generates a stream by repeating the elements of the provided stream forever. This stream is not bounded.

*
{@code
     *     Stream stream = Stream.of("tick", "tock");
     *     Stream cyclingStream = StreamsUtils.cycle(stream);
     *     List collect = cyclingStream.limit(9).collect(Collectors.toList());
     *     // The collect list is ["tick", "tock", "tick", "tock", "tick", "tock", "tick", "tock", "tick"]
     * }
*

The returned spliterator is ORDERED.

* * @param stream The stream to cycle on. Will throw a NullPointerException if null. * @param The type of the elements of the provided stream. * @return A cycling stream. */ public static Stream cycle(Stream stream) { Objects.requireNonNull(stream); CyclingSpliterator spliterator = CyclingSpliterator.of(stream.spliterator()); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close).flatMap(identity()); } /** *

Generates a stream by regrouping the elements of the provided stream and putting them in a substream. The number * of elements regrouped is the groupingFactor.

*

Example:

*
{@code
     *     Stream stream = Stream.of("a0", "a1", "a2", "a3");
     *     Stream> groupingStream = StreamsUtils.group(stream, 2);
     *     List> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList());
     *     // The collect list is [["a0", "a1"]["a2", "a3"]]
     * }
*

If the provided stream is empty, then the returned stream contains an empty stream.

*

The groupingFactor should be greater of equals than 2. A grouping factor of 0 does not make * sense. A grouping factor of 1 is in fact a mapping with a Stream::of. An * IllegalArgumentException will be thrown if a non valid groupingFactor is provided.

*

An IllegalArgumentException will also be thrown if the provided stream is not ORDERED

*

The returned stream has the same characteristics as the provided stream, and is thus ORDERED.

*

All the returned substreams are guaranteed to produce groupingFactor elements. So there might be * elements from the provided stream that will not be consumed in the grouped stream.

* * @param stream The stream to be grouped. Will throw a NullPointerException if null. * @param groupingFactor The grouping factor, should be greater of equal than 2. * @param The type of the elements of the provided stream. * @return A grouped stream of streams. */ public static Stream> group(Stream stream, int groupingFactor) { Objects.requireNonNull(stream); GroupingSpliterator spliterator = GroupingSpliterator.of(stream.spliterator(), groupingFactor); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream by regrouping the elements of the provided stream and putting them in a substream. * This grouping operation scans the elements of the stream using the open predicate. If this * predicate is true, then it begins to add the elements of the stream in a substream. It will continue to add * them until an element that matches the close predicate is met.

*

The basic group operation includes the opening and the closing elements in the substreams. You can also * provide two booleans if you need to customize this behavior.

*

Example:

*
{@code
     *     Stream stream = Stream.of("o", "a0", "a1", "a2", "c", "a3", "a4, "o", "a5", "c");
     *     Stream> groupingStream = StreamsUtils.group(stream, "o"::equals, "c"::equals);
     *     List> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList());
     *     // The collect list is [["o", "a0", "a1", "a2", "c"]["o", "a5", "c"]]
     * }
*

If the provided stream is empty, then the returned stream contains an empty stream.

*

An IllegalArgumentException will also be thrown if the provided stream is not ORDERED

*

The returned stream has the same characteristics as the provided stream, and is thus ORDERED.

*

A {@code {@link NullPointerException}} is thrown if the stream to be grouped or one of the predicate is null.

* * @param stream The stream to be grouped. Will throw a NullPointerException if null. * @param open The predicate used to check for an opening element. * @param close The predicate used to check for an closing element. * @param The type of the elements of the provided stream. * @return A grouped stream of streams. */ public static Stream> group(Stream stream, Predicate open, Predicate close) { Objects.requireNonNull(stream); Objects.requireNonNull(open); Objects.requireNonNull(close); return group(stream, open, true, close, true); } /** *

Generates a stream by regrouping the elements of the provided stream and putting them in a substream. * This grouping operation scans the elements of the stream using the splitter predicate. When this predicate * returns true, then the elements of the stream are accumulated in a subtream, until the splitter predicate * is true again. In this case, a new substream is created, until the elements of the provided stream are * exhausted.

*

In the case where several consecutive splitting elements are met, no empty stream is generated. * The splitting element is added only once to the next substream if needed.

*

The boolean included controls whether the splitting element is added to the substreams or not.

*

A {@code {@link NullPointerException}} is thrown if the stream to be grouped or the splitter is null.

* * @param stream The stream to be grouped. Will throw a NullPointerException if null. * @param splitter The predicate used to check for an splitting element. * @param included if true: includes the splitting element at the beginning of each substream * @param The type of the elements of the provided stream. * @return A grouped stream of streams. */ public static Stream> group(Stream stream, Predicate splitter, boolean included) { Objects.requireNonNull(stream); Objects.requireNonNull(splitter); GroupingOnSplittingSpliterator spliterator = GroupingOnSplittingSpliterator.of(stream.spliterator(), splitter, included); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream by regrouping the elements of the provided stream and putting them in a substream. * This grouping operation scans the elements of the stream using the splitter predicate. When this predicate * returns true, then the elements of the stream are accumulated in a subtream, until the splitter predicate * is true again. In this case, a new substream is created, until the elements of the provided stream are * exhausted.

*

In this case, the splitting element is not added to the substream.

*

In the case where several consecutive splitting elements are met, no empty stream is generated.

*

A {@code {@link NullPointerException}} is thrown if the stream to be grouped or the splitter is null.

* * @param stream The stream to be grouped. Will throw a NullPointerException if null. * @param splitter The predicate used to check for an splitting element. * @param The type of the elements of the provided stream. * @return A grouped stream of streams. */ public static Stream> group(Stream stream, Predicate splitter) { Objects.requireNonNull(stream); Objects.requireNonNull(splitter); return group(stream, splitter, true); } /** *

Generates a stream by regrouping the elements of the provided stream and putting them in a substream. * This grouping operation scans the elements of the stream using the open predicate. If this * predicate is true, then it begins to add the elements of the stream in a substream. It will continue to add * them until an element that matches the close predicate is met.

*

Adding the opening and the closing elements is controlled by the two boolean parameters * openingElementIncluded and closingElementIncluded.

*

Example:

*
{@code
     *     Stream stream = Stream.of("o", "a0", "a1", "a2", "c", "a3", "a4, "o", "a5", "c");
     *     Stream> groupingStream = StreamsUtils.group(stream, "o"::equals, false, "c"::equals, false);
     *     List> collect = groupingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList());
     *     // The collect list is [["a0", "a1", "a2"]["a5"]]
     * }
*

If the provided stream is empty, then the returned stream contains an empty stream.

*

An IllegalArgumentException will also be thrown if the provided stream is not ORDERED

*

The returned stream has the same characteristics as the provided stream, and is thus ORDERED.

*

A {@code {@link NullPointerException}} is thrown if the stream to be grouped or one of the predicate is null.

* * @param stream The stream to be grouped. Will throw a NullPointerException if null. * @param open The predicate used to check for an opening element. * @param openingElementIncluded if true : includes the opening element in each substream * @param close The predicate used to check for an closing element. * @param closingElementIncluded if true : includes the closing element in each substream * @param The type of the elements of the provided stream. * @return A grouped stream of streams. */ public static Stream> group( Stream stream, Predicate open, boolean openingElementIncluded, Predicate close, boolean closingElementIncluded) { Objects.requireNonNull(stream); Objects.requireNonNull(open); Objects.requireNonNull(close); GroupingOnGatingSpliterator spliterator = GroupingOnGatingSpliterator.of(stream.spliterator(), open, openingElementIncluded, close, closingElementIncluded); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream by repeating the elements of the provided stream. The number of times an element is * repeated is given by the repeating factor. *

Example:

*
{@code
     *     Stream stream = Stream.of("a0", "a1", "a2", "a3");
     *     Stream repeatingStream = StreamsUtils.repeat(stream, 3);
     *     List collect = repeatingStream.collect(Collectors.toList());
     *     // The collect list is ["a0", "a0", "a0", "a1", "a1", "a1", "a2", "a2", "a2", "a3", "a3", "a3"]
     * }
*

If the provided stream is empty, then the returned stream is also empty.

*

The repeatingFactor should be greater of equals than 2. A repeating factor of 0 does not make * sense. A repeating factor of 1 is in fact the identity operation. An * IllegalArgumentException will be thrown if a non valid repeatingFactor is provided.

*

An IllegalArgumentException will be thrown if a non SIZED stream is provided. * Believe me, trying to repeat an infinite stream is not a good idea.

*

The repeating of the provided stream should no lead to the producing of more than Long.MAX_VALUE. * Weird effects will occur in that case.

*

A NullPointerException is thrown if the provided stream is null.

*

The returned stream is ORDERED.

* * @param stream The stream to be repeated. Will throw a NullPointerException if null. * @param repeatingFactor The repeating factor, should be greater of equal than 2. * @param The type of the elements of the provided stream. * @return A repeating stream. */ public static Stream repeat(Stream stream, int repeatingFactor) { Objects.requireNonNull(stream); RepeatingSpliterator spliterator = RepeatingSpliterator.of(stream.spliterator(), repeatingFactor); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream by grouping the elements of the provided stream, and by advancing one by one the first * element of the next substream. The number of elements of the substreams is the rolling factor. *

Example:

*
{@code
     *     Stream stream = Stream.of("a0", "a1", "a2", "a3", "a4", "a5", "a6", "a7");
     *     Stream> rollingStream = StreamsUtils.roll(stream, 3);
     *     List> collect = rollingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList());
     *     // The collect list is [["a0", "a1", "a2"],
     *                             ["a1", "a2", "a3"],
     *                             ["a2", "a3", "a4"],
     *                             ["a3", "a4", "a5"],
     *                             ["a4", "a5", "a6"],
     *                             ["a5", "a6", "a7"]]
     * }
*

If the provided stream is empty, then the returned stream contains an empty stream.

*

The rollingFactor should be greater of equals than 2. A rolling factor of 0 does not make * sense. A rolling factor of 1 is in fact a mapping with a Stream::of. An * IllegalArgumentException will be thrown if a non valid rollingFactor is provided.

*

An IllegalArgumentException will also be thrown is a non ORDERED stream is * provided.

*

The returned stream has the same characteristics as the provided stream, and is thus ORDERED.

*

All the returned substreams are guaranteed to produce rollingFactor elements. So there might be * elements from the provided stream that will not be consumed in the grouped stream.

*

A NullPointerException is thrown if the provided stream is null.

*

An IllegalArgumentException is thrown if the rollingFactor is less than 2, * or if the provided stream is non-ordered.

* * @param stream The stream to be rolled. Will throw a NullPointerException if null. * @param rollingFactor The rolling factor, should be greater of equal than 2. * @param The type of the elements of the provided stream. * @return A rolling stream of streams. */ public static Stream> roll(Stream stream, int rollingFactor) { Objects.requireNonNull(stream); RollingSpliterator spliterator = RollingSpliterator.of(stream.spliterator(), rollingFactor); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream by taking one element of the provided streams at a time, and putting them in a substream. *

Example:

*
{@code
     *     Stream stream0 = Stream.of("a00", "a01", "a02", "a03");
     *     Stream stream1 = Stream.of("a10", "a11", "a12", "a13");
     *     Stream stream2 = Stream.of("a20", "a21", "a22", "a23");
     *     Stream stream3 = Stream.of("a30", "a31", "a32", "a33");
     *     Stream> traversingStream = StreamsUtils.traverse(stream0, stream1, stream2, stream3);
     *     List> collect = traversingStream.map(st -> st.collect(Collectors.toList())).collect(Collectors.toList());
     *     // The collect list is [["a00", "a10", "a20", "a30"],
     *                             ["a01", "a11", "a21", "a31"],
     *                             ["a02", "a12", "a22", "a32"],
     *                             ["a03", "a13", "a23", "a33"]]
     * }
*

An IllegalArgumentException is thrown if there is only one stream provided in the varargs. In * that case, the traversing would be a mapping with Stream::of.

*

An IllegalArgumentException is also thrown if one of the provided streams is not ORDERED.

*

The characteristics of the returned stream is the bitwise AND of all the characteristics of * the provided streams. In most of the cases, all these streams will share the same characteristics, so in this * case it will be the same as well. The returned stream is thus ORDERED.

*

A NullPointerException is thrown if one of the provided streams is null.

* * @param streams The streams to be traversed. Will throw a NullPointerException if null. * @param The type of the elements of the provided stream. * @return A traversing stream of streams. */ @SafeVarargs public static Stream> traverse(Stream... streams) { Arrays.stream(streams).forEach(Objects::requireNonNull); @SuppressWarnings("unchecked") Spliterator[] spliterators = Stream.of(streams).map(Stream::spliterator).toArray(Spliterator[]::new); TraversingSpliterator spliterator = TraversingSpliterator.of(spliterators); return StreamSupport.stream(spliterator, Arrays.stream(streams).allMatch(Stream::isParallel)) .onClose(() -> Arrays.stream(streams).forEach(Stream::close)); } /** *

Generates a stream by taking one element of the provided streams at a time, and putting them in the * resulting stream. *

Example:

*
{@code
     *     Stream stream0 = Stream.of("a00", "a01", "a02");
     *     Stream stream1 = Stream.of("a10", "a11", "a12");
     *     Stream stream2 = Stream.of("a20", "a21", "a22");
     *     Stream> weavingStream = StreamsUtils.traverse(stream0, stream1, stream2);
     *     List collect = weavingStream.map(st -> st.collect(Collectors.toList()).collect(Collectors.toList());
     *     // The collect list is ["a00", "a10", "a20", "a01", "a11", "a21", "a02", "a12", "a22"]
     * }
*

An IllegalArgumentException is thrown if there is only one stream provided in the varargs. In * that casse, the traversing would be a mapping with Stream::of.

*

An IllegalArgumentException is also thrown if one of the provided streams is not ORDERED.

*

The characteristics of the returned stream is the bitwise AND of all the characteristics of * the provided streams. In most of the cases, all these streams will share the same characteristics, so in this * case it will be the same as well. The returned stream is thus ORDERED.

*

The returned stream will stop producing elements as soon as one of the provided stream stops to do so. * So some of the elements of the provided streams might not be consumed.

*

A NullPointerException is thrown if one of the provided streams is null.

* * @param streams The streams to be weaved. Will throw a NullPointerException if null. * @param The type of the elements of the provided stream. * @return A weaved stream. */ @SafeVarargs public static Stream weave(Stream... streams) { Arrays.stream(streams).forEach(Objects::requireNonNull); @SuppressWarnings("unchecked") Spliterator[] spliterators = Stream.of(streams).map(Stream::spliterator).toArray(Spliterator[]::new); WeavingSpliterator spliterator = WeavingSpliterator.of(spliterators); return StreamSupport.stream(spliterator, Arrays.stream(streams).allMatch(Stream::isParallel)) .onClose(() -> Arrays.stream(streams).forEach(Stream::close)); } /** *

Generates a stream by taking one element at a time from each of the provided streams, and transforming them * using the provided bifunction. *

Example:

*
{@code
     *     Stream  stream0 = Stream.of("a", "b", "c", "d");
     *     Stream stream1 = Stream.of(0, 1, 2, 3);
     *     Bifunction zipper = (s, i) -> s + "-" + i;
     *     Stream zippingStream = StreamsUtils.zip(stream0, stream1, zipper);
     *     List collect = zippingStream.collect(Collectors.toList());
     *     // The collect list is ["a-0", "b-1", "c-2", "d-3"]
     * }
*

The characteristics of the returned spliterator is the bitwise AND of the characteristics of * the provided streams. Those streams should have the same characteristics, so there will be no change on * this point.

*

The returned stream will stop producing elements as soon as one of the provided stream stops to do so. * So some of the elements of the provided streams might not be consumed.

*

A NullPointerException will be thrown if the zipper generates a null value. So * the returned stream is guaranteed not to have null values.

*

In case you cannot be sure that your zipper returns null, then you can provide a * zipper than wraps its result in an Optional (using the * Optional.ofNullable() factory method), and flat map the returned stream. Your nulls will then * be silently removed from the stream.

* * @param stream1 The first stream to be zipped. Will throw a NullPointerException if null. * @param stream2 The second stream to be zipped. Will throw a NullPointerException if null. * @param zipper The bifunction used to transform the elements of the two streams. * Will throw a NullPointerException if null. * @param The type of the elements of the first provided stream. * @param The type of the elements of the second provided stream. * @param The type of the elements of the returned stream. * @return A zipped stream. */ public static Stream zip(Stream stream1, Stream stream2, BiFunction zipper) { Objects.requireNonNull(stream1); Objects.requireNonNull(stream2); Objects.requireNonNull(zipper); ZippingSpliterator.Builder builder = new ZippingSpliterator.Builder<>(); ZippingSpliterator spliterator = builder.with(stream1.spliterator()) .and(stream2.spliterator()) .mergedBy(zipper) .build(); return StreamSupport.stream(spliterator, stream1.isParallel() && stream2.isParallel()) .onClose(() -> { stream1.close(); stream2.close(); }); } /** *

Generates a stream by validating the elements of an input stream one by one using the provided predicate.

*

An element of the input stream is said to be valid if the provided predicate returns true for this element.

*

A valid element is replaced in the returned stream by the application of the provided function for valid * elements. A non-valid element is replaced by the other function.

*

A NullPointerException will be thrown if one of the provided elements is null.

* * @param stream the stream to be validated. Will throw a NullPointerException if null. * @param validator the predicate used to validate the elements of the stream. * Will throw a NullPointerException if null. * @param transformingIfValid the function applied to the valid elements. * Will throw a NullPointerException if null. * @param transformingIfNotValid the function applied to the non-valid elements. * Will throw a NullPointerException if null. * @param the type of the elements of the input stream. * @param the type of the elements of the returned stream. * @return the validated and transformed stream. */ public static Stream validate(Stream stream, Predicate validator, Function transformingIfValid, Function transformingIfNotValid) { Objects.requireNonNull(stream); Objects.requireNonNull(validator); Objects.requireNonNull(transformingIfValid); Objects.requireNonNull(transformingIfNotValid); ValidatingSpliterator.Builder builder = new ValidatingSpliterator.Builder<>(); ValidatingSpliterator spliterator = builder.with(stream.spliterator()) .validatedBy(validator) .withValidFunction(transformingIfValid) .withNotValidFunction(transformingIfNotValid) .build(); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream by validating the elements of an input stream one by one using the provided predicate.

*

An element of the input stream is said to be valid if the provided predicate returns true for this element.

*

A valid element is transmitted to the returned stream without any transformation. A non-valid element is * replaced by the application of the provided unary operator.

*

This function calls the general version of validate() with special parameters.

*

A NullPointerException will be thrown if one of the provided elements is null.

* * @param stream the stream to be validated. Will throw a NullPointerException if null. * @param validator the predicate used to validate the elements of the stream. * Will throw a NullPointerException if null. * @param transformingIfNotValid the operator applied to the non-valid elements. * Will throw a NullPointerException if null. * @param the type of the stream and the returned stream. * @return the validated and transformed stream. */ public static Stream validate(Stream stream, Predicate validator, UnaryOperator transformingIfNotValid) { return validate(stream, validator, Function.identity(), transformingIfNotValid); } /** *

Generates a stream identical to the provided stream until the interruptor predicate is false for one element. * At that time, the returned stream stops.

*

A NullPointerException will be thrown if the provided stream of the interruptor predicate is null.

*

If you are using Java 9, then yo should use Stream.takeWhile(Predicate).

* * @param stream the input stream. Will throw a NullPointerException if null. * @param interruptor the predicate applied to the elements of the input stream. * Will throw a NullPointerException if null. * @param the type of the stream and the returned stream. * @return a stream that is a copy of the input stream, until the interruptor becomes false. */ public static Stream interrupt(Stream stream, Predicate interruptor) { Objects.requireNonNull(stream); Objects.requireNonNull(interruptor); InterruptingSpliterator spliterator = InterruptingSpliterator.of(stream.spliterator(), interruptor); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream that does not generate any element, until the validator becomes true for an element of * the provided stream. From this point, the returns stream is identical to the provided stream.

*

If you are using Java 9, then yo should use Stream.dropWhile(Predicate).

*

A NullPointerException will be thrown if the provided stream of the validator predicate is null.

* * @param stream the input stream. Will throw a NullPointerException if null. * @param validator the predicate applied to the elements of the input stream. * Will throw a NullPointerException if null. * @param the type of the stream and the returned stream. * @return a stream that starts when the validator becomes true. */ public static Stream gate(Stream stream, Predicate validator) { Objects.requireNonNull(stream); Objects.requireNonNull(validator); GatingSpliterator spliterator = GatingSpliterator.of(stream.spliterator(), validator); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream that is computed from a provided stream following two steps.

*

The first steps consists in building a rolling stream with the rollingFactor passed as * a parameter. This rolling stream is the same the one built using the roll() method. *

*

Then each substream is collected using the collector passed as the third parameter.

*

The result is set up in a stream that has the same number of elements as the provided stream, * minus the size of the window width, to preserve consistency of each collection.

*

A NullPointerException will be thrown if the provided stream or the collector is null.

* * @param stream the processed stream * @param rollingFactor the size of the window to apply the collector on * @param collector the collector to be applied * @param the type of the provided stream * @param the type of the returned stream * @return a stream in which each value is the collection of the provided stream */ public static Stream shiftingWindowCollect(Stream stream, int rollingFactor, Collector collector) { Objects.requireNonNull(stream); Objects.requireNonNull(collector); return roll(stream, rollingFactor).map(str -> str.collect(collector)); } /** *

Generates a stream that is computed from a provided stream following two steps.

*

The first steps maps this stream to an IntStream that is then rolled following * the same principle as the roll() method. This steps builds a Stream<IntStream>. *

*

Then the average() method is called on each IntStream using a mapper, and a * DoubleStream of averages is returned.

*

The resulting stream has the same number of elements as the provided stream, * minus the size of the window width, to preserve consistency of each collection.

*

A NullPointerException will be thrown if the provided stream or the mapper is null.

* * @param stream the processed stream * @param rollingFactor the size of the window to apply the collector on * @param mapper the mapper applied * @param the type of the provided stream * @return a stream in which each value is the average of the provided stream */ public static DoubleStream shiftingWindowAveragingInt(Stream stream, int rollingFactor, ToIntFunction mapper) { Objects.requireNonNull(stream); Objects.requireNonNull(mapper); IntStream intStream = stream.mapToInt(mapper); return shiftingWindowAveragingInt(intStream, rollingFactor); } /** *

Generates a stream that is computed from a provided int stream by first rolling it in the same * way as the roll() method does. The average is then computed on each substream, to * form the final double stream. No boxing / unboxing is conducted in the process. *

The resulting stream has the same number of elements as the provided stream, * minus the size of the window width, to preserve consistency of each collection.

*

A NullPointerException will be thrown if the provided stream is null.

* * @param intStream the processed stream * @param rollingFactor the size of the window to apply the collector on * @return a stream in which each value is the collection of the provided stream */ public static DoubleStream shiftingWindowAveragingInt(IntStream intStream, int rollingFactor) { Objects.requireNonNull(intStream); RollingOfIntSpliterator ofIntSpliterator = RollingOfIntSpliterator.of(intStream.spliterator(), rollingFactor); return StreamSupport.stream(ofIntSpliterator, intStream.isParallel()) .onClose(intStream::close) .mapToDouble(subStream -> subStream.average().getAsDouble()); } /** *

Generates a stream that is computed from a provided stream following two steps.

*

The first steps maps this stream to an LongStream that is then rolled following * the same principle as the roll() method. This steps builds a Stream<LongStream>. *

*

Then the average() method is called on each LongStream using a mapper, and a * DoubleStream of averages is returned.

*

The resulting stream has the same number of elements as the provided stream, * minus the size of the window width, to preserve consistency of each collection.

*

A NullPointerException will be thrown if the provided stream or the mapper is null.

* * @param stream the processed stream * @param rollingFactor the size of the window to apply the collector on * @param mapper the mapper applied * @param the type of the provided stream * @return a stream in which each value is the collection of the provided stream */ public static DoubleStream shiftingWindowAveragingLong(Stream stream, int rollingFactor, ToLongFunction mapper) { Objects.requireNonNull(stream); Objects.requireNonNull(mapper); LongStream longStream = stream.mapToLong(mapper); return shiftingWindowAveragingLong(longStream, rollingFactor); } /** *

Generates a stream that is computed from a provided long stream by first rolling it in the same * way as the roll() method does. The average is then computed on each substream, to * form the final double stream. No boxing / unboxing is conducted in the process. *

The resulting stream has the same number of elements as the provided stream, * minus the size of the window width, to preserve consistency of each collection.

*

A NullPointerException will be thrown if the provided stream is null.

* * @param longStream the processed stream * @param rollingFactor the size of the window to apply the collector on * @return a stream in which each value is the collection of the provided stream */ public static DoubleStream shiftingWindowAveragingLong(LongStream longStream, int rollingFactor) { Objects.requireNonNull(longStream); RollingOfLongSpliterator ofLongSpliterator = RollingOfLongSpliterator.of(longStream.spliterator(), rollingFactor); return StreamSupport.stream(ofLongSpliterator, longStream.isParallel()) .onClose(longStream::close) .mapToDouble(subStream -> subStream.average().getAsDouble()); } /** *

Generates a stream that is computed from a provided stream following two steps.

*

The first steps maps this stream to an DoubleStream that is then rolled following * the same principle as the roll() method. This steps builds a Stream<DoubleStream>. *

*

Then the average() method is called on each DoubleStream using a mapper, and a * DoubleStream of averages is returned.

*

The resulting stream has the same number of elements as the provided stream, * minus the size of the window width, to preserve consistency of each collection.

*

A NullPointerException will be thrown if the provided stream or the mapper is null.

* * @param stream the processed stream * @param rollingFactor the size of the window to apply the collector on * @param mapper the mapper applied * @param the type of the provided stream * @return a stream in which each value is the collection of the provided stream */ public static DoubleStream shiftingWindowAveragingDouble(Stream stream, int rollingFactor, ToDoubleFunction mapper) { Objects.requireNonNull(stream); Objects.requireNonNull(mapper); DoubleStream doubleStream = stream.mapToDouble(mapper); return shiftingWindowAveragingDouble(doubleStream, rollingFactor); } /** *

Generates a stream that is computed from a provided double stream by first rolling it in the same * way as the roll() method does. The average is then computed on each substream, to * form the final double stream. No boxing / unboxing is conducted in the process. *

The resulting stream has the same number of elements as the provided stream, * minus the size of the window width, to preserve consistency of each collection.

*

A NullPointerException will be thrown if the provided stream is null.

* * @param doubleStream the processed stream * @param rollingFactor the size of the window to apply the collector on * @return a stream in which each value is the collection of the provided stream */ public static DoubleStream shiftingWindowAveragingDouble(DoubleStream doubleStream, int rollingFactor) { Objects.requireNonNull(doubleStream); RollingOfDoubleSpliterator ofDoubleSpliterator = RollingOfDoubleSpliterator.of(doubleStream.spliterator(), rollingFactor); return StreamSupport.stream(ofDoubleSpliterator, doubleStream.isParallel()) .onClose(doubleStream::close) .mapToDouble(subStream -> subStream.average().getAsDouble()); } /** *

Generates a stream that is computed from a provided stream following two steps.

*

The first steps maps this stream to an IntStream that is then rolled following * the same principle as the roll() method. This steps builds a Stream<IntStream>. *

*

Then int summary statistics are computed on each IntStream using a collect() call, * and a Stream<IntSummaryStatistics> is returned.

*

The resulting stream has the same number of elements as the provided stream, * minus the size of the window width, to preserve consistency of each collection.

*

A NullPointerException will be thrown if the provided stream or the mapper is null.

* * @param stream the processed stream * @param rollingFactor the size of the window to apply the collector on * @param mapper the mapper applied * @param the type of the provided stream * @return a stream in which each value is the collection of the provided stream */ public static Stream shiftingWindowSummarizingInt(Stream stream, int rollingFactor, ToIntFunction mapper) { Objects.requireNonNull(stream); Objects.requireNonNull(mapper); IntStream intStream = stream.mapToInt(mapper); return shiftingWindowSummarizingInt(intStream, rollingFactor); } /** *

Generates a stream that is computed from a provided int stream by first rolling it in the same * way as the roll() method does. Then a summarizing int operation is applied on each * substream to form the final int summary stream. No boxing / unboxing is conducted in the process. *

The resulting stream has the same number of elements as the provided stream, * minus the size of the window width, to preserve consistency of each collection.

*

A NullPointerException will be thrown if the provided stream is null.

* * @param intStream the processed stream * @param rollingFactor the size of the window to apply the collector on * @return a stream in which each value is the collection of the provided stream */ public static Stream shiftingWindowSummarizingInt(IntStream intStream, int rollingFactor) { Objects.requireNonNull(intStream); RollingOfIntSpliterator ofIntSpliterator = RollingOfIntSpliterator.of(intStream.spliterator(), rollingFactor); return StreamSupport.stream(ofIntSpliterator, intStream.isParallel()) .onClose(intStream::close) .map( str -> str.collect( IntSummaryStatistics::new, IntSummaryStatistics::accept, IntSummaryStatistics::combine ) ); } /** *

Generates a stream that is computed from a provided stream following two steps.

*

The first steps maps this stream to an LongStream that is then rolled following * the same principle as the roll() method. This steps builds a Stream<LongStream>. *

*

Then long summary statistics are computed on each LongStream using a collect() call, * and a Stream<LongSummaryStatistics> is returned.

*

The resulting stream has the same number of elements as the provided stream, * minus the size of the window width, to preserve consistency of each collection.

*

A NullPointerException will be thrown if the provided stream or the mapper is null.

* * @param stream the processed stream * @param rollingFactor the size of the window to apply the collector on * @param mapper the mapper applied * @param the type of the provided stream * @return a stream in which each value is the collection of the provided stream */ public static Stream shiftingWindowSummarizingLong(Stream stream, int rollingFactor, ToLongFunction mapper) { Objects.requireNonNull(stream); Objects.requireNonNull(mapper); LongStream longStream = stream.mapToLong(mapper); return shiftingWindowSummarizingLong(longStream, rollingFactor); } /** *

Generates a stream that is computed from a provided long stream by first rolling it in the same * way as the roll() method does. Then a summarizing long operation is applied on each * substream to form the final long summary stream. No boxing / unboxing is conducted in the process. *

The resulting stream has the same number of elements as the provided stream, * minus the size of the window width, to preserve consistency of each collection.

*

A NullPointerException will be thrown if the provided stream is null.

* * @param longStream the processed stream * @param rollingFactor the size of the window to apply the collector on * @return a stream in which each value is the collection of the provided stream */ public static Stream shiftingWindowSummarizingLong(LongStream longStream, int rollingFactor) { Objects.requireNonNull(longStream); RollingOfLongSpliterator ofLongSpliterator = RollingOfLongSpliterator.of(longStream.spliterator(), rollingFactor); return StreamSupport.stream(ofLongSpliterator, longStream.isParallel()) .onClose(longStream::close) .map( str -> str.collect( LongSummaryStatistics::new, (longSummaryStatistics, value) -> longSummaryStatistics.accept(value), LongSummaryStatistics::combine ) ); } /** *

Generates a stream that is computed from a provided stream following two steps.

*

The first steps maps this stream to a DoubleStream that is then rolled following * the same principle as the roll() method. This steps builds a Stream<DoubleStream>. *

*

Then double summary statistics are computed on each DoubleStream using a collect() call, * and a Stream<DoubleSummaryStatistics> is returned.

*

The resulting stream has the same number of elements as the provided stream, * minus the size of the window width, to preserve consistency of each collection.

*

A NullPointerException will be thrown if the provided stream is null.

* * @param stream the processed stream * @param rollingFactor the size of the window to apply the collector on * @param mapper the mapper applied * @param the type of the provided stream * @return a stream in which each value is the collection of the provided stream */ public static Stream shiftingWindowSummarizingDouble(Stream stream, int rollingFactor, ToDoubleFunction mapper) { Objects.requireNonNull(stream); Objects.requireNonNull(mapper); DoubleStream doubleStream = stream.mapToDouble(mapper); return shiftingWindowSummarizingLong(doubleStream, rollingFactor); } /** *

Generates a stream that is computed from a provided double stream by first rolling it in the same * way as the roll() method does. Then a summarizing double operation is applied on each * substream to form the final double summary stream. No boxing / unboxing is conducted in the process. *

The resulting stream has the same number of elements as the provided stream, * minus the size of the window width, to preserve consistency of each collection.

*

A NullPointerException will be thrown if the provided stream is null.

* * @param doubleStream the processed stream * @param rollingFactor the size of the window to apply the collector on * @return a stream in which each value is the collection of the provided stream */ public static Stream shiftingWindowSummarizingLong(DoubleStream doubleStream, int rollingFactor) { Objects.requireNonNull(doubleStream); RollingOfDoubleSpliterator ofDoubleSpliterator = RollingOfDoubleSpliterator.of(doubleStream.spliterator(), rollingFactor); return StreamSupport.stream(ofDoubleSpliterator, doubleStream.isParallel()) .onClose(doubleStream::close) .map( str -> str.collect( DoubleSummaryStatistics::new, DoubleSummaryStatistics::accept, DoubleSummaryStatistics::combine ) ); } /** *

Generates a stream of Map.Entry<E, E> elements with all the cartesian product of the * elements of the provided stream with itself.

*

For a stream {a, b, c}, a stream with the following elements is created: * {(a, a), (a, b), (a, c), (b, a), (b, b), (b, c), (c, a), (c, b), (c, c)}, where * (a, b) is the Map.Entry with key a and value b.

*

A NullPointerException will be thrown if the provided stream is null.

* * @param stream the processed stream * @param the type of the provided stream * @return a stream of the cartesian product */ public static Stream> crossProduct(Stream stream) { Objects.requireNonNull(stream); CrossProductOrderedSpliterator spliterator = CrossProductOrderedSpliterator.of(stream.spliterator()); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream of Map.Entry<E, E> elements with all the cartesian product of the * elements of the provided stream with itself, without the entries in which the key and the * value is equal.

*

For a stream {a, b, c}, a stream with the following elements is created: * {(a, b), (a, c), (b, a), (b, c), (c, a), (c, b)}, where * (a, b) is the Map.Entry with key a and value b.

*

A NullPointerException will be thrown if the provided stream is null.

* * @param stream the processed stream * @param the type of the provided stream * @return a stream of the cartesian product */ public static Stream> crossProductNoDoubles(Stream stream) { Objects.requireNonNull(stream); CrossProductOrderedSpliterator spliterator = CrossProductOrderedSpliterator.noDoubles(stream.spliterator()); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream of Map.Entry<E, E> elements with all the cartesian product of the * elements of the provided stream with itself, in which the entries are such that the key is * strictly lesser than the value, using the provided comparator.

*

For a stream {a, b, c}, a stream with the following elements is created: * {(a, b), (a, c), (b, c)}, where * (a, b) is the Map.Entry with key a and value b.

*

A NullPointerException will be thrown if the provided stream or comparator is null.

* * @param stream the processed stream * @param comparator the comparator or the elements of the provided stream * @param the type of the provided stream * @return a stream of the cartesian product */ public static Stream> crossProductOrdered(Stream stream, Comparator comparator) { Objects.requireNonNull(stream); Objects.requireNonNull(comparator); CrossProductOrderedSpliterator spliterator = CrossProductOrderedSpliterator.ordered(stream.spliterator(), comparator); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream of Map.Entry<E, E> elements with all the cartesian product of the * elements of the provided stream with itself, in which the entries are such that the key is * strictly lesser than the value, using the natural order of E.

*

For a stream {a, b, c}, a stream with the following elements is created: * {(a, b), (a, c), (b, c)}, where * (a, b) is the Map.Entry with key a and value b.

*

A NullPointerException will be thrown if the provided stream is null.

* * @param stream the processed stream * @param the type of the provided stream * @return a stream of the cartesian product */ public static > Stream> crossProductNaturallyOrdered(Stream stream) { Objects.requireNonNull(stream); CrossProductOrderedSpliterator spliterator = CrossProductOrderedSpliterator.ordered(stream.spliterator(), Comparator.naturalOrder()); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream only composed of the greatest elements of the provided stream, compared using the provided * comparator.

*

A NullPointerException will be thrown if the provided stream or the comparator is null.

* * @param stream the processed stream * @param comparator the comparator used to compare the elements of the stream * @param the type of the provided stream * @return a filtered stream */ public static Stream filteringAllMax(Stream stream, Comparator comparator) { Objects.requireNonNull(stream); Objects.requireNonNull(comparator); FilteringAllMaxSpliterator spliterator = FilteringAllMaxSpliterator.of(stream.spliterator(), comparator); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream only composed of the greatest elements of the provided stream, compared using their * natural order.

*

A NullPointerException will be thrown if the provided stream is null.

* * @param stream the processed stream * @param the type of the provided stream * @return a filtered stream */ public static > Stream filteringAllMax(Stream stream) { Objects.requireNonNull(stream); return filteringAllMax(stream, Comparator.naturalOrder()); } /** *

Generates a stream composed of the N greatest values of the provided stream, compared using the * provided comparator. If there are no duplicates in the provided stream, then the returned stream will have * N values, assuming that the input stream has more than N values.

*

All the duplicates are copied in the returned stream, so in this case the number of elements in the * returned stream may be greater than N. In this case, the number of different values is not guaranteed, and * may be lesser than N.

*

Since this operator extract maxes according to the provided comparator, the result is sorted from the * greatest element to the smallest, thus in the decreasing order, according to the provided comparator.

*

The provided implementation uses and insertion buffer of size N to keep the N maxes, as well as a hash * map to keep the duplicates. This implementation becomes less and less efficient as N grows.

*

A NullPointerException will be thrown if the provided stream or the comparator is null.

*

An IllegalArgumentException is thrown if N is lesser than 1.

* * @param stream the processed stream * @param numberOfMaxes the number of different max values that should be returned. Note that the total number of * values returned may be larger if there are duplicates in the stream * @param comparator the comparator used to compare the elements of the stream * @param the type of the provided stream * @return the filtered stream */ public static Stream filteringMaxValues(Stream stream, int numberOfMaxes, Comparator comparator) { Objects.requireNonNull(stream); Objects.requireNonNull(comparator); FilteringMaxValuesSpliterator spliterator = FilteringMaxValuesSpliterator.of(stream.spliterator(), numberOfMaxes, comparator); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream composed of the N greatest values of the provided stream, compared using the * natural order. This method calls the filteringMaxValues() with the natural order comparator, * please refer to this javadoc for details. .

*

A NullPointerException will be thrown if the provided stream.

*

An IllegalArgumentException is thrown if N is lesser than 1.

* * @param stream the processed stream * @param numberOfMaxes the number of different max values that should be returned. Note that the total number of * values returned may be larger if there are duplicates in the stream * @param the type of the provided stream * @return the filtered stream */ public static > Stream filteringMaxValues(Stream stream, int numberOfMaxes) { Objects.requireNonNull(stream); return filteringMaxValues(stream, numberOfMaxes, Comparator.naturalOrder()); } /** *

Generates a stream composed of the N greatest different values of the provided stream, compared using the * provided comparator. If there are no duplicates in the provided stream, then the returned stream will have * N values, assuming that the input stream has more than N values.

*

All the duplicates are removed in the returned stream, so in this case the number of elements in the * returned stream may be lesser than N. In this case, the total number of values is not guaranteed, and * may be lesser than N.

*

Since this operator extract maxes according to the provided comparator, the result is sorted from the * greatest element to the smallest, thus in the decreasing order, according to the provided comparator.

*

The provided implementation uses and insertion buffer of size N to keep the N maxes. * This implementation becomes less and less efficient as N grows.

*

A NullPointerException will be thrown if the provided stream or the comparator is null.

*

An IllegalArgumentException is thrown if N is lesser than 1.

* * @param stream the processed stream * @param numberOfMaxes the number of different max values that should be returned. Note that the total number of * values returned may be larger if there are duplicates in the stream * @param comparator the comparator used to compare the elements of the stream * @param the type of the provided stream * @return the filtered stream */ public static Stream filteringMaxKeys(Stream stream, int numberOfMaxes, Comparator comparator) { Objects.requireNonNull(stream); Objects.requireNonNull(comparator); FilteringMaxKeysSpliterator spliterator = FilteringMaxKeysSpliterator.of(stream.spliterator(), numberOfMaxes, comparator); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream composed of the N greatest different values of the provided stream, compared using the * natural order. This method calls the filteringMaxKeys() with the natural order comparator, * please refer to this javadoc for details.

*

A NullPointerException will be thrown if the provided stream is null.

*

An IllegalArgumentException is thrown if N is lesser than 1.

* * @param stream the processed stream * @param numberOfMaxes the number of different max values that should be returned. Note that the total number of * values returned may be larger if there are duplicates in the stream * @param the type of the provided stream * @return the filtered stream */ public static > Stream filteringMaxKeys(Stream stream, int numberOfMaxes) { Objects.requireNonNull(stream); return filteringMaxKeys(stream, numberOfMaxes, Comparator.naturalOrder()); } /** *

Generates a stream composed of the accumulation of its elements, through the use of the provided binary * operator.

*

For the stream {@code Stream.of(1, 1, 1, 1)}, and the {@code Integer::sum} operator, * the following stream is returned: {@code Stream.of(1, 2, 3, 4)}

*

For the stream {@code Stream.of(1, 2, 5, 3)}, and the {@code Integer::max} operator, * the following stream is returned: {@code Stream.of(1, 2, 5, 5)}

*

A NullPointerException will be thrown if the provided stream or the operator is null.

*

A IllegalArgumentException will be thrown if the provided stream is not ordered.

* * @param stream the processed stream * @param operator the binary operator used to accumulate the elements of the stream * @param the type of the provided stream * @return the accumulated stream */ public static Stream accumulate(Stream stream, BinaryOperator operator) { Objects.requireNonNull(stream); Objects.requireNonNull(operator); AccumulatingSpliterator spliterator = AccumulatingSpliterator.of(stream.spliterator(), operator); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } /** *

Generates a stream composed of the accumulation of its elements, through the use of the provided binary * operator.

*

For the stream {@code Stream.of(1, 1, 1, 1)}, and the {@code Integer::sum} operator, * the following stream is returned: {@code Stream.of(1, 2, 3, 4)}

*

For the stream {@code Stream.of(1, 2, 5, 3)}, and the {@code Integer::max} operator, * the following stream is returned: {@code Stream.of(1, 2, 5, 5)}

*

A NullPointerException will be thrown if the provided stream or the operator is null.

*

A IllegalArgumentException will be thrown if the provided stream is not ordered.

* * @param stream the processed stream of entries * @param operator the binary operator used to accumulate the values of the stream * @param the type of the keys of the provided stream * @param the type of the values provided stream * @return the accumulated stream */ public static Stream> accumulateEntries(Stream> stream, BinaryOperator operator) { Objects.requireNonNull(stream); Objects.requireNonNull(operator); AccumulatingEntriesSpliterator spliterator = AccumulatingEntriesSpliterator.of(stream.spliterator(), operator); return StreamSupport.stream(spliterator, stream.isParallel()).onClose(stream::close); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy