
net.sf.staccatocommons.collections.stream.Stream Maven / Gradle / Ivy
/**
* Copyright (c) 2010-2012, The StaccatoCommons Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
package net.sf.staccatocommons.collections.stream;
import java.io.IOException;
import java.io.Serializable;
import java.io.Writer;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import net.sf.staccatocommons.collections.EmptySourceException;
import net.sf.staccatocommons.collections.iterable.Iterables;
import net.sf.staccatocommons.collections.restrictions.Projection;
import net.sf.staccatocommons.collections.restrictions.Repeatable;
import net.sf.staccatocommons.defs.Applicable;
import net.sf.staccatocommons.defs.Applicable2;
import net.sf.staccatocommons.defs.Evaluable;
import net.sf.staccatocommons.defs.Evaluable2;
import net.sf.staccatocommons.defs.Executable;
import net.sf.staccatocommons.defs.ProtoMonad;
import net.sf.staccatocommons.defs.Thunk;
import net.sf.staccatocommons.defs.function.Function;
import net.sf.staccatocommons.defs.function.Function2;
import net.sf.staccatocommons.defs.partial.ContainsAware;
import net.sf.staccatocommons.defs.partial.SizeAware;
import net.sf.staccatocommons.defs.reduction.Reduction;
import net.sf.staccatocommons.defs.tuple.Tuple2;
import net.sf.staccatocommons.defs.type.NumberType;
import net.sf.staccatocommons.iterators.thriter.Thriterator;
import net.sf.staccatocommons.lang.None;
import net.sf.staccatocommons.lang.Option;
import net.sf.staccatocommons.lang.tuple.Tuples;
import net.sf.staccatocommons.restrictions.check.NonNull;
import net.sf.staccatocommons.restrictions.check.NotNegative;
/**
* A {@link Stream} is a lazy, rich-interfaced, {@link Iterable}, chained
* functional-style object that can retrieve and process an arbitrary - and
* potentially unbound - amount of other objects of a parameterized type. Such
* objects are called elements, and are generated by another object, called
* source. Some examples of elements and its source are:
*
* - Elements in a collection
* - Files in a directory
* - Characters in a string
* - Lines in a file
* - Rows in a result set
* - Virtually anything that has sense to iterate through
*
*
* Streams have the following properties:
*
* - Operation oriented: A stream represents a single and eventually complex
* transformation over a source of objects; it is not a
* container
* - Reference Semantics: A stream internal state is meaningless, and Streams
* do not override Object's {@link #equals(Object)}, {@link #hashCode()} nor
* {@link #toString()}
* - Non persistent: Streams are not {@link Serializable} Thus, they should
* not be used as attributes of long-living objects.
* - One-Message: Given a stream instance, only one message can be sent to it,
* sending more than one message to it has an undefined result, as a
* consequence, it may be iterated only once. There are three exceptions to this
* rule, though:
*
* - Methods inherited from {@link Object} like {@link #toString()} and
* {@link #hashCode()}. None of those methods affect the transformation nor the
* underlying source
* - {@link #isEmpty()}: it may be sent multiple times and grants consistent
* results as long as no other message except of those at previous item is sent.
* This message does not affect the transformation, but may modify the
* underlying source
* - Streams returned by class or instance methods annotated with
* {@link Repeatable}, like {@link #force()} or {@link Streams#cons(Object)}.
* Such streams may be reused and receive any message any number of times, and
* grant consistent results, including repeatable iteration order.
*
*
* - Lazy projections: all of the - many - transformations exposed by streams
* that are annotated as {@link Projection} are lazy. Such methods do also work
* with very large o potentially infinte streams. Methods not annotated that way
* will not work on infinite streams, as they will never end
* normally
*
*
* Streams provide messages for performing random access,
* however they do not warrant to implement them in an efficient manner,
* and it normally depends on the underlying source.
*
* Concrete, simple streams, collection handling-oriented, may be instantiated
* through {@link Streams} class. Other concrete streams are be provided by
* other staccato-commons libraries.
*
* Aside from these concrete streams, client code may also implement new ones.
* In order to do that, it must not implement this interface
* directly, but inherit from {@link AbstractStream}, which implements all
* methods except of {@link #iterator()}
*
*
* @author fbulgarelli
*
* @param
* the type of object the stream is source of
*/
public interface Stream extends //
ContainsAware, //
Iterable, //
ProtoMonad, Stream, A>, //
SizeAware {
// Iterable
Thriterator iterator();
// ProtoMonad
/**
* Executes the given {@link Executable} block for each element.
*
* This message is equivalent to a for-each loop over this {@link Stream}
*
* @param block
* @since 1.2
*/
void forEach(@NonNull Executable super A> block);
/**
* Maps the given side effect over this stream, by answering a {@link Stream}
* that lazily applies the given side effect over each stream elements, and
* retrieves them.
*
* @param block
* @return {@code map(Functions.impure(block)}
* @since 1.1 original version, replaced by {@link #forEach(Executable)}
* @since 1.2 current version, incompatible with previous 1.1
*
*/
@Projection
Stream each(@NonNull Executable super A> block);
/**
* Transforms each element using the given function
*
* @param
* @param function
* the mapper used to transform each element, applying it
* @return a new {@link Stream} projection that will retrieve the result of
* applying the given function to each element
*/
@Projection
Stream map(@NonNull Applicable super A, ? extends B> function);
/**
* Preserves elements that satisfy the given predicate
*
* Example:
*
* //Answers stream [hello, world], which has only strings whose length is 5
* Streams.cons("a", "hello", "world", "of", "streams", "!").filter(length().equal(5));
*
*
* @param predicate
* @return a new {@link Stream} projection that will retrieve only elements
* that evaluate to true
*/
@Projection
Stream filter(@NonNull Evaluable super A> predicate);
/**
* Preserves all elements but those that are equal to the given one.
*
* Equivalent to {@code filter(Predicates.equal(element).not())}
*
* @param element
* @return a {@link Stream} that retrieves all elements that are not equal to
* the given one
*/
@Projection
Stream skip(@NonNull A element);
// Specialized filtering
/**
* Preserves all elements while they satisfy the given predicate
*
* @param predicate
* @return a new {@link Stream} projection that will retrieve all elements
* from this stream, as long as none of them evaluates to false.
*/
@Projection
Stream takeWhile(@NonNull Evaluable super A> predicate);
/**
* Preserves up to N elements. It this Stream size is shorter than the given
* amountOfElements
, the resulting stream will retrieve the same
* elements than this stream.
*
* @param amountOfElements
* @return a new {@link Stream} projection that will retrieve up to N elements
*/
@Projection
Stream take(@NotNegative int amountOfElements);
/**
* Discards all elements while they satisfy the given predicate
*
* @param predicate
* @return a new {@link Stream} projection that will skip all elements as long
* as they satisfy the given {@link Evaluable}
*/
@Projection
Stream dropWhile(@NonNull Evaluable super A> predicate);
/**
* Discards up to N elements from this {@link Stream}. Is the Stream size is
* shorter than the given amountOfElements
, the resulting stream
* will be empty.
*
* @param amountOfElements
* the amount of elements to discard
* @return a new {@link Stream} that discards up to the given
* amountOfElements
*/
@Projection
Stream drop(@NotNegative int amountOfElements);
/**
* Answers a stream that is a substream of this one. The substream begins at
* the specified {@code beginIndex}, and extends to the element at index
* {@code endIndex} - 1, if it has enough elements, or up to its last element,
* otherwise.
*
* The resulting stream is always finite, and satisfies that
* {@code size() <= endIndex - beginIndex}
*
* As a particular case, if {@code beginIndex == endIndex}, an empty stream is
* returned.
*
* Examples:
*
* Streams.from("hamburger").slice(4, 8).joinStrings(""); //answers "urge"
* Streams.from("smiles").slice(1, 5).joinStrings(""); //answers "mile"
* Streams.from("hello world!").slice(6, 309).joinStrings(""); //answers "world!"
* Streams.enumerate(1,20).slice(5,5).toList(); //answers []
*
*
* @param beginIndex
* the lower bound, inclusive
* @param endIndex
* the upper bound, exclusive
* @return {@code drop(beginIndex).take(endIndex - beginIndex)}
*/
@Projection
Stream slice(@NotNegative int beginIndex, @NotNegative int endIndex);
//Partitioning and splitting
// TODO
// Tuple2, Stream> splitBeforeIndex(@NotNegative int position);
//
// Tuple2, Stream> splitBefore(A element);
//
/***
* Splits stream elements into two lists using a predicate - elements that
* evaluate to true will be returned in the first component, the rest will be
* returned in the second component
*
* @param predicate
* @return a new {@link Tuple2} that contains this stream partitioned into two
* lists.
*/
@NonNull
Tuple2, List> partition(@NonNull Evaluable super A> predicate);
/**
* Splits stream elements into two ordered streams, that support random
* access. This method just converts list returned by
* {@link #partition(Evaluable)} into Streams.
*
* @param predicate
* @return a new {@link Tuple2} that contains this stream partitioned into two
* other streams.
*/
@NonNull
Tuple2, Stream> streamPartition(@NonNull Evaluable super A> predicate);
// Specialized Mapping
/**
* Transforms each element using the given function.
*
* Example:
*
*
* import static import net.sf.staccatocommons.util.Strings.*;
* //Answers [HELLO, WORLD, STREAMS]
* Streams.cons("hello", "world", "streams").map(toUpperCase());
*
*
*
* import static net.sf.staccatocommons.numbers.NumberTypes.*;
* ...
* //answers Stream [6, 9, 11, 26]
* Streams.cons(5, 8, 10, 25).map(add(1)).println();
*
* @param
* @param function
* the mapper used to transform each element, applying it
* @return a new {@link Stream} projection that will retrieve the result of
* applying the given function to each element
*/
@Projection
Stream map(@NonNull Function super A, ? extends B> function);
// FlatMapping
/**
* Transformes each element into an iterable using the given function, and
* concatenates (flattens) the result
*
* @param
* @param function
* @return a new {@link Stream} that will retrieve the result of transforming
* each element and concatenating those transformations
*/
@Projection
Stream flatMap(@NonNull Function super A, ? extends Iterable extends B>> function);
/**
* Transformes each element into an array using the given function, and
* concatenates (flattens) the result
*
* @param
* @param function
* @return a new {@link Stream} that will retrieve the result of transforming
* each element and concatenating those trsansformations
*/
@Projection
Stream flatMapArray(@NonNull Function super A, ? extends B[]> function);
// Reversing
/**
* Reverses this Stream, by returning a new Stream that retrieves elements in
* the inverse order of this Stream.
*
* This may not be a {@link Projection}, depending on if the stream's source
* permits it.
*
* @return a new {@link Stream} that retrieves elements in the inverse order
* of this stream.
*/
@NonNull
Stream reverse();
// Searching
/**
* Returns the {@link #head()} of this {@link Stream}
*
* The different between {@link #head()} and {@link #any()} is strictly semantic:
* use this message instead of {@link #head()} whenever the code needs an
* unspecified element, rather than the first element of the stream.
*
* @return {@link #head()}
* @throws EmptySourceException
* if this {@link Stream} has no elements.
*/
A any() throws EmptySourceException;
/**
* Returns the {@link #head()} of the given {@link Stream}, just like {@link #any()},
* but as an option. If {@link Stream} has no elements, instead of throwing a
* {@link EmptySourceException}, it returns {@link None}
*
* @return Option.some(element)
if there is at least one element,
* or Option.none()
, otherwise.
*/
@NonNull
Option anyOrNone();
/**
* Shorthand for anyOrNone().valueOrNull()
*
* @return anyOrNone().valueOrNull()
*/
A anyOrNull();
/**
* Shorthand for anyOrNone().valueOrElse(thunk)
*
* @param thunk
*
* @return anyOrNone().valueOrElse(thunk)
*/
A anyOrElse(@NonNull Thunk thunk);
/**
* Shorthand for anyOrNone().valueOrElse(value)
*
* @param value
* @return anyOrNone().valueOrElse(value)
*/
A anyOrElse(A value);
/**
* Looks for a element that satisfies the given {@link Evaluable}. If such
* element does not exist, throws {@link NoSuchElementException}
*
* @param predicate
* @return the first elements that the predicate satisfies, if exists.
* @throws EmptySourceException
* if this stream is empty
* @throws NoSuchElementException
* if no element matches the predicate.
*/
A find(@NonNull Evaluable super A> predicate) throws EmptySourceException, NoSuchElementException;
/**
* Looks for an element that satisfies the given {@link Evaluable}. If such
* element exists, returns some(element)
. Otherwise, returns
* {@link None}.
*
* @param predicate
* @return None if no element matches the predicate, or some(element) if at
* least one exists. As a particular case, this method will return
* {@link None} if {@link Stream} is empty, regardless of the given
* predicate
*/
@NonNull
Option findOrNone(@NonNull Evaluable super A> predicate);
/**
* Looks for an element that satisfies the given {@link Evaluable}. If such
* element exists, returns it. Otherwise, returns null.
*
* @param predicate
* @return null if no element matches the predicate, or an element that
* satisfies it, if at least one exists. As a particular case, this
* method will return null if {@link Stream} is empty, regardless of
* the given predicate
*/
A findOrNull(@NonNull Evaluable super A> predicate);
/**
* Looks for an element that satisfies the given {@link Evaluable}. If such
* element exists, returns it. Otherwise, returns the given thunk's value.
*
* @param predicate
* @return thunk.value()
if no element matches the predicate, or
* an element that satisfies it, if at least one exists. As a
* particular case, this method will return the thunk's value if
* {@link Stream} is empty, regardless of the given predicate
*/
A findOrElse(@NonNull Evaluable super A> predicate, @NonNull Thunk extends A> thunk);
/**
* Looks for an element that satisfies the given {@link Evaluable}. If such
* element exists, returns it. Otherwise, returns the given
* element
.
*
* @param predicate
* @return findOrElse(predicate, Thunks.constant(element))
*/
A findOrElse(@NonNull Evaluable super A> predicate, @NonNull A element);
// Testing
/**
* Tests if all elements satisfy the given {@link Evaluable}
*
* @param predicate
* an {@link Evaluable} to evaluate each element
* @return if all the elements evaluate to true
*/
boolean all(@NonNull Evaluable super A> predicate);
/**
* Tests if all elements are equal
*
* @return if all the elements are equal
*/
boolean allEquiv();
/**
* Tests if all elements are equivalent, using the given
* equivTest
*
* @param equivTest
* an {@link Evaluable2} used to testing if an element is equivalent
* to another
* @return if all the elements are equal
*/
boolean allEquivBy(Evaluable2 super A, ? super A> equivTest);
/**
* Tests if at least one element satisfies the given {@link Evaluable}
*
* @param predicate
* an {@link Evaluable} to evaluate each element
* @return if any element evaluate to true
*/
boolean any(@NonNull Evaluable super A> predicate);
/***
* Tests if any of the elements in this stream is contained in by the given
* collection, using {@link Collection#contains(Object)}
*
* @param elements
* @return if the intersection between this stream and the given elements is
* not empty
* @since 2.3
*/
boolean intersects(Collection extends A> other);
/***
* Tests if any of the elements in this stream is among the given elements
*
* @param elements
* @return if the intersection between this stream and the given elements is not empty
* @since 2.3
*/
boolean intersects(A ... elements);
/**
* Test that the elements of this stream are equal to the elements of the
* given array, and in the same order.
*
* @param elements
* @return true
if this stream has the same number of elements
* that the given array, and each pair formed by elements of this
* stream and the given array at same position are equal.
* false
otherwise
*/
boolean equiv(A... elements);
/**
* Test that the elements of this stream are equal to the elements of the
* given {@link Iterable}, and in the same order.
*
* @param other
* @return true if this stream has the same number of elements that
* other
, and each pair formed by elements of this
* stream and given iterable
at same position are equal.
* false
otherwise
*/
boolean equiv(Iterable extends A> other);
/**
* Test that the elements of this stream are equal to the elements of the
* given {@link iterator}, and in the same order.
*
* @param iterable
* @return true if this stream has the same number of elements that
* other
, and each pair formed by elements of this
* stream and given iterable
at same position are equal.
* false
otherwise
* @since 2.2
*/
boolean equiv(Iterator extends A> other);
/**
* Test that the elements of this stream are equivalent to the elements of the
* given {@link Iterable}, and in the same order, using the given
* equalityTest
for determining equivalence between elements.
*
* @param equalityTest
* @param iterable
*
* @return true
if this stream has the same number of elements
* that the given iterable
, and each pair formed by
* elements of this stream and given iterable
at same
* position satisfies the given {@link Evaluable2}
*/
boolean equivBy(@NonNull Evaluable2 super A, ? super A> equalityTest, @NonNull Iterable extends A> iterable);
/**
* Test that the elements of this stream are equivalent to the elements of the
* given {@link Iterable}, and in the same order, using the given
* equalityTest
for determining equivalence between elements.
*
* @param equalityTest
* @param iterable
*
* @return true
if this stream has the same number of elements
* that other
, and each pair formed by
* elements of this stream and other
at same
* position satisfies the given {@link Evaluable2}
* @since 2.2
*/
boolean equivBy(@NonNull Evaluable2 super A, ? super A> equalityTest, @NonNull Iterator extends A> other);
/**
* Test that the elements of this stream are equivalent to the given
* elements
, and in the same order, using the given
* equalityTest
for determining equivalence between elements.
*
* @param equalityTest
* @param iterable
*
* @return true
if this stream has the same number of elements
* that the given elements
, and each pair formed by
* elements of this stream and given elements
at same
* position satisfies the given {@link Evaluable2}
*/
boolean equivBy(@NonNull Evaluable2 super A, ? super A> equalityTest, A... elements);
/**
* Test that the elements of this stream are equivalent to the elements of the
* given {@link Iterable}, and in the same order, using the
* Equiv.on(function)
for determining equivalence between
* elements.
*
* @param function
* @param iterable
*
* @return true
if this stream has the same number of elements
* that the given iterable
, and each pair formed by
* elements of this stream and given iterable
at same
* position satisfies the {@link Evaluable2}
* Equiv.on(function)
*/
boolean equivOn(@NonNull Applicable super A, ? extends B> function, @NonNull Iterable extends A> iterable);
/**
* Test that the elements of this stream are equivalent to the elements of the
* given {@link Iterator}, and in the same order, using the
* Equiv.on(function)
for determining equivalence between
* elements.
*
* @param function
* @param iterable
*
* @return true
if this stream has the same number of elements
* that the given {@link Iterator}, and each pair formed by
* elements of this stream and given {@link Iterator} at same
* position satisfies the {@link Evaluable2}
* Equiv.on(function)
* @since 2.2
*/
boolean equivOn(@NonNull Applicable super A, ? extends B> function, @NonNull Iterator extends A> other);
/**
* Test that the elements of this stream are equivalent to the given elements,
* and in the same order, using the Equiv.on(function)
for
* determining equivalence between elements.
*
* @param function
* @param iterable
*
* @return true
if this stream has the same number of elements
* that the given elements
, and each pair formed by
* elements of this stream and the given elements
at same
* position satisfies the {@link Evaluable2}
* Equiv.on(function)
*/
boolean equivOn(@NonNull Applicable super A, ? extends B> function, A... elements);
// Folding
/**
* (Left)folds this {@link Stream} using an initial value and the given
* two-arg function, producing a single aggregated result from all the Stream
* elements.
*
* This consist of taking the initial value and a {@link Stream} element,
* applying the function to them, and then repeating the process with this
* result as the next initial value and the next element from the stream. The
* last returned value is the folding result.
*
* @param
* @param initial
* @param function
* @return the aggregates result
* @see Folds
*/
B fold(B initial, @NonNull Applicable2 super B, ? super A, ? extends B> function);
/**
* (Left)folds the tail of this {@link Stream} using the first element of the
* stream as initial value, producing a single aggregated result from all the
* Stream elements.
*
* @param function
* @return the folding result
* @throws EmptySourceException
* if this {@link Stream} is empty
* @see #fold(Object, Applicable2)
* @see Folds
*
*/
A reduce(@NonNull Applicable2 super A, ? super A, ? extends A> function) throws EmptySourceException;
/**
* Answers the result of aggregating this stream using the given
* reduction
*
* @param reduction
* @return the folding result
* @since 1.2
*/
//TODO check exception here
B reduce(Reduction super A, B> reduction) throws NoSuchElementException;
/**
* (Left)folds this {@link Stream} concatenating each elements toString with a
* separator
*
* @param separator
* @return the string representation of each element concatenated using a
* separator
*/
@NonNull
String joinStrings(@NonNull String separator);
/**
* Answers the sum of the elements of this {@link Stream} using the given
* {@link NumberType}
*
* @param numberType
* @return the result of adding each element, or zero, if this stream is empty
* @see Iterables#sum(Iterable, NumberType)
*/
@NonNull
A sum(@NonNull NumberType numberType);
/**
* Answers the product of the elements of this {@link Stream} using the given
* {@link NumberType}
*
* @param numberType
* @return the result of multiplying each element, or one, if this stream is
* empty
* @see Iterables#product(Iterable, NumberType)
*/
@NonNull
A product(@NonNull NumberType numberType);
/**
* Answers the average of the stream elements, using the given
* {@link NumberType} for performing addition and division.
*
* @param numberType
* @return the average of the stream elements
* @throws ArithmeticException
* if the stream is empty and number type does not support zero
* division
*/
A average(@NonNull NumberType numberType) throws ArithmeticException;
/**
* Answers the number of element that satisfy the given predicate
*
* @param predicate
* @return filter(predicate).size()
* @since 2.1
*/
int countOf(Evaluable super A> predicate);
// Sorting
/**
* Sorts this Stream, using their element's natural ordering
*
* @return a new {@link Stream}
*/
@Projection
Stream sort();
/**
* Sorts this Stream, using the given comparator
*
* @param comparator
* @return a new {@link Stream}
*/
@Projection
Stream sortBy(@NonNull Comparator comparator);
/**
* Sorts this Stream, using Compare.on(function)
as comparator
*
* @param
* @param function
* @return a new {@link Stream}
*/
@Projection
> Stream sortOn(Applicable super A, B> function);
/**
* Answers the min element of the stream, using the given
* comparator
to compare elements.
*
* @param comparator
* @return the minimum element.
* @throws EmptySourceException
* if the stream is empty.
*/
@NonNull
A minimumBy(@NonNull Comparator super A> comparator) throws EmptySourceException;
/**
* Answers the minimum element of the stream, using the given
* Compare.on(function)
to compare elements.
*
* @param function
* @return the minimum element.
* @throws EmptySourceException
* if the stream is empty.
*/
> A minimumOn(@NonNull Applicable super A, B> function) throws EmptySourceException;
/**
* Answers the minimum element of the stream, using elements natural order.
*
* @return the minimum element.
* @throws EmptySourceException
* if the stream is empty.
* @throws ClassCastException
* if elements are not comparable
*/
@NonNull
A minimum() throws ClassCastException, EmptySourceException;
/**
* Answers the maximum element of the stream, using the given
* comparator
to compare elements.
*
* @param comparator
* @return the maximum element.
* @throws EmptySourceException
* if the stream is empty.
*/
@NonNull
A maximumBy(@NonNull Comparator super A> comparator) throws EmptySourceException;
/**
* Answers the maximum element of the stream, using the given
* Compare.on(function)
to compare elements.
*
* @param function
* @return the maximum element.
* @throws EmptySourceException
* if the stream is empty.
*/
> A maximumOn(@NonNull Applicable super A, B> function) throws EmptySourceException;
/**
* Answers the maximum element of the stream, using elements natural order.
*
* @return the maximum element.
* @throws EmptySourceException
* if the stream is empty.
* @throws ClassCastException
* if elements are not comparable
*/
@NonNull
A maximum() throws ClassCastException, EmptySourceException;
// Appending
/**
* Equivalent to {@link #concat(Iterable)}
*
* @deprecated use {@link #concat(Iterable)} instead
*/
@Projection
Stream append(@NonNull Iterable other);
/**
* Concatenates this
with other
*
* It answers an {@link Stream} that retrieves elements from this Stream, and
* then, after its last element, from the given iterable.
*
* As a particular case, if this Stream is infinite, the resulting Stream will
* retrieve the same elements than this one.
*
* @param other
* @return a new {@link Stream}
* @since 2.2
*/
@Projection
Stream concat(@NonNull Iterable extends A> other);
/**
* Concatenates this
with the given elements
*
* It answers an {@link Stream} that retrieves elements from this Stream, and
* then, after its last element, the given elements.
*
* As a particular case, if this Stream is infinite, the resulting Stream will
* retrieve the same elements than this one.
*
* Example:
*
* //answers the Stream [0, 1, 2, 3]
* Streams.cons(0, 1).concat(2, 3);
*
*
* @param elements the element to add at the end of the stream
* @return a new {@link Stream}
* @since 2.2
*/
@Projection
Stream concat(@NonNull A ... elements);
/**
* Concatenates this
with the given {@link Iterator}
*
* It answers an {@link Stream} that retrieves elements from this Stream, and
* then, after its last element, the given iterator's elements.
*
* As a particular case, if this Stream is infinite, the resulting Stream will
* retrieve the same elements than this one.
*
* @param other the iterator whose elements will be added at the end of the stream
* @return a new {@link Stream}
* @since 2.2
*/
Stream concat(@NonNull Iterator extends A> other);
/**
* Concatenates this Stream with the undefined Stream. Equivalent to
* concat(Streams.undefined())
*
* @return a new {@link Stream}, {@link Repeatable} as long as {@code this} is
* repeatable
* @see Streams#undefined()
*/
@Projection
Stream appendUndefined();
/**
* Adds an element as the last one of the stream.
*
* @param element
* @return a new {@link Stream} that retrieves this {@link Stream} elements,
* and then, the given element
*/
@Projection
Stream append(A element);
/**
* Equivalent to {@link #delayedAppend(Thunk)}.
*
* @deprecated use {@link #delayedAppend(Thunk)} instead
*/
@Deprecated
@Projection
Stream append(@NonNull Thunk thunk);
/**
* Adds an element's thunk as the last one of the stream.
*
* @param thunk
* @return a new {@link Stream} that retrieves this {@link Stream} elements,
* and then, the value of the given thunk
* @since 2.2
*/
@Projection
Stream delayedAppend(@NonNull Thunk thunk);
/**
* Adds an element as the first one of the stream.
*
* @param element
* @return a new {@link Stream} that retrieves the given element
,
* and then, this {@link Stream} elements.
*/
@Projection
Stream prepend(A element);
/**
* Equivalent to {@link #delayedPrepend(Thunk)}
*
* @deprecated use {@link #delayedPrepend(Thunk)}
*/
@Deprecated
@Projection
Stream prepend(@NonNull Thunk thunk);
/**
* Adds an element's thunk as the first one of the stream.
*
* @param thunk
* @return a new {@link Stream} that retrieves the value of the given
* thunk
, and then, this {@link Stream} elements.
*/
@Projection
Stream delayedPrepend(@NonNull Thunk thunk);
// Inserting
/**
* Inserts {@code element} at {@code index - 1}. If stream has not enough
* elements, that is, stream size is less than or equal to {@code index}
* elements, the element is inserted at its end.
*
* This message ensures that for any finite stream, and any element and index
*
*
* stream.insertBeforeIndex(element, index).containsBeforeIndex(element, index + 1)
*
* is true
.
*
* Examples:
*
*
* Streams.cons(4, 5, 6).insertBeforeIndex(0, 2); //answers [4, 5, 0, 6]
* Streams.repeat(1).take(4).insertBeforeIndex(0, 2); //answers [1, 1, 0, 1, 1]
* Streams.repeat(1).take(4).insertBeforeIndex(0, 20); //answers [1, 1, 1, 1, 0]
*
*
* @param element the element to insert
* @param index the index before inserting it
* @return a {@link Stream} that lazily inserts the given element before the
* given index
* @since 2.2
*/
Stream insertBeforeIndex(A element, @NotNegative int index);
/**
* Inserts {@code element} before the first occurrence of {@code reference}.
* If {@code reference} is not contained by this stream, the element is inserted at
* its end.
*
* This message ensures that for any finite stream, and any element and reference
*
* stream.insertBefore(element, ref).containsBefore(element, ref)
*
* is true
.
*
* Examples:
*
* Streams.cons('a', 'b', 'c').insertBefore('x', 'a'); //answers [x,a,b,c]
* Streams.cons('a', 'b', 'c').insertBefore('x', 'c'); //answers [a,b,x,c]
* Streams.cons('a', 'b', 'c').insertBefore('x', 'd'); //answers [a,b,c,x]
*
*
* @param element
* @param reference
* @return a {@link Stream} that lazily inserts the given element before the
* reference
* @since 2.2
*/
@Projection
Stream insertBefore(A element, A reference);
// Branching
/**
* Answers a stream that retrieves a tuple per each element, formed by the
* original element as the first component, and the result of applying the
* given function to it as the second component.
*
* This message is equivalent to {@code map(Tuples.clone(function))}
*
*
* @param function
* the function to apply to each element
* @return a new {@link Stream}
* @see Tuples#clone(Applicable)
* @since 1.2
*/
@Projection
Stream> clone(Applicable super A, ? extends B> function);
/**
* Answers a Stream of pairs, where each one contains both results of applying
* the given functions. Equivalent to
* this.map(Tuples.branch(function0, function1))
*
* @param
* @param
* @param function0
* @param function1
* @return a new {@link Stream}
* @since 1.2
* @see Tuples#branch(Applicable, Applicable)
*/
@Projection
Stream> branch(Applicable super A, ? extends B> function0,
Applicable super A, ? extends C> function1);
// Zipping
/**
* Returns a {@link Stream} formed by the result of applying the given
* function
to each pair of elements from this
and
* the given iterable
.
*
* If either this
or the given iterable is shorter than the other
* given number of elements, the remaining elements of this are discarded
*
*
* Example:
*
*
* //Answers the stream [1 + 4, 2 + 5] == [5, 7];
* Streams.cons(1, 2).zipWith(integer().add(), 4, 5);
*
*
* @param elements
* the elements to zip with this Stream
* @param function
* the function to apply to each pair
* @return a new Stream which is the result of applying the given
* {@link Applicable2} to each pair this Stream and the elements. The
* resulting Stream size is the minimum of this size and the number of
* elements
* @see Iterables#zip(Iterable, Iterable)
*/
@Projection
Stream zipWith(Function2 super A, ? super B, C> function, @NonNull B... elements);
/**
* Returns a {@link Stream} formed by the result of applying the given
* function
to each pair of elements from this
and
* the given iterable
.
*
* If either this
or the given iterable is shorter than
* the other one, the remaining elements are discarded.
*
* @param
* the type to the iterable
to zip with this
* {@link Stream}
* @param
* the resulting Stream element type
* @param iterable
* the {@link Iterable} to zip with this Stream
* @param function
* the function to apply to each pair
* @return a new Stream formed applying the given {@link Applicable2} to each
* pair this Stream and the given iterable. The resulting Stream size
* is the minimum of both iterables sizes, or infinite, if both this
* and iterable
are
* @see Iterables#zip(Iterable, Iterable)
*/
@Projection
Stream zipWith(Function2 super A, ? super B, C> function, @NonNull Iterable other);
/**
* Returns a {@link Stream} formed by the result of applying the given
* function
to each pair of elements from this
and
* the other
.
*
* If either this
or the given {@link Iterator} is shorter than
* the other one, the remaining elements are discarded.
*
* @param
* the type to the iterable
to zip with this
* {@link Stream}
* @param
* the resulting Stream element type
* @param other
* the {@link Iterator} to zip with this Stream
* @param function
* the function to apply to each pair
* @return a new Stream formed applying the given {@link Applicable2} to each
* pair this Stream and the given iterator. The resulting Stream size
* is the minimum of both iterables sizes, or infinite, if both this
* and other
are
* @see Iterables#zip(Iterable, Iterable)
* @since 2.2
*/
Stream zipWith(Function2 super A, ? super B, C> function, @NonNull Iterator other);
/**
* Equivalent to {@link #zipWith(Function2, Iterable)}, with arguments
* interchanged
*
* @deprecated use {@link #zipWith(Function2, Iterable)}
*/
@Deprecated
@Projection
Stream zip(@NonNull Iterable iterable, Function2 super A, ? super B, C> function);
/**
* Returns a {@link Stream} formed by by pair of element from
* this
and the given elements
.
*
* If either this
or the given array is shorter than the other
* one, the remaining elements are discarded.
*
* Examples:
*
*
* //Answers the stream [(0, a), (1,b), (2,c)]
* Streams.cons(0, 1, 2).zip('a', 'b', 'c');
*
*
*
* //Answers true
* Streams
* .from("hello")
* .zip(Streams.from("world!"))
* .equiv(
* _('h', 'w'),
* _('e', 'o'),
* _('l', 'r'),
* _('l', 'l'),
* _('o', 'd')); //notice the last '!' was discarded
*
*
* @param
* @param iterable
* @return a new Stream formed applying the given {@link Applicable2} to each
* pair this Stream and the given elements. The resulting Stream size
* is the minimum of both iterables sizes.
* @see #zip(Iterable, Function2)
* @since 2.2
*/
@Projection
Stream> zip(@NonNull B... elements);
/**
* Returns a {@link Stream} formed by by pair of element from
* this
and the given iterable
.
*
* If either this
or the given iterable is shorter than
* the other one, the remaining elements are discarded.
*
* @param
* @param iterable
* @return a new Stream formed applying the given {@link Applicable2} to each
* pair this Stream and the given iterable. The resulting Stream size
* is the minimum of both iterables sizes, or infinite, if both this
* and iterable
are
* @see Iterables#zip(Iterable, Iterable)
* @see #zip(Iterable, Function2)
*/
@Projection
Stream> zip(@NonNull Iterable iterable);
/**
* Returns a {@link Stream} formed by by pair of element from
* this
and the given {@link Iterator}.
*
* If either this
or other
is shorter than
* the other one, the remaining elements are discarded.
*
* @param
* @param other
* @return a new Stream formed applying the given {@link Applicable2} to each
* pair this Stream and the given iterator. The resulting Stream size
* is the minimum of both iterables sizes, or infinite, if both this
* and other
are
* @see Iterables#zip(Iterable, Iterable)
* @see #zip(Iterable, Function2)
* @since 2.2
*/
Stream> zip(@NonNull Iterator other);
// Printing
/**
* Prints the stream elements to an appendable, like {@link StringBuilder} or
* a {@link Writer}
*
* @param destination
* the appendable were print stream elements
* @throws IOException
* if any io error occurs
*/
void print(java.lang.Appendable destination) throws IOException;
/**
* Prints the stream elements to {@link System#out}
*
* @throws IOException
* if any io error occurs
*/
void print();
/**
* Prints the stream elements to an appendable, like {@link StringBuilder} or
* a {@link Writer}, followed by a newline character
*
* @param destination
* the appendable were print stream elements
* @throws IOException
* if any io error occurs
*/
void println(java.lang.Appendable o) throws IOException;
/**
* Prints the stream elements to {@link System#out}, followed by a newline
* character. Equivalent to {@code println(System.out)}
*
* @throws IOException
* if any io error occurs
*/
void println();
/**
* Prints the stream elements to a string
*
* @return a string with the stream elements
*/
String printString();
// Copying
/**
* Converts this {@link Stream} into a Set, by adding all its elements to a
* new Set. The resulting Set is {@link Serializable} and non-lazy.
*
* @return a new {@link Set} that contains all elements retrieved from this
* {@link Stream}
*/
@NonNull
Set toSet();
/**
* * Converts this {@link Stream} into a List, by adding all its elements to a
* new List. The resulting List is {@link Serializable} and non-lazy.
*
* @return a new {@link List} that contains all elements retrieved from this
* {@link Stream}
*/
@NonNull
List toList();
/**
* Creates a new array that has the same elements that the retrived by this
* {@link Stream}
*
* @param clazz
* the array component class
* @return a new array
*/
@NonNull
A[] toArray(@NonNull Class super A> clazz);
/**
* Equivalent to {@link #memoize()}
*
* @deprecated the exact name of this concept is memoization, not
* memorization. Use {@link #memoize()} instead
*/
@Deprecated
@Repeatable
@Projection
Stream memorize();
/**
* Memoizes stream elements and their order, by answering a lazy stream with
* {@link Repeatable} iteration order that caches elements evaluated during
* iteration.
*
* @return a new {@link Stream} that memoizes elements evaluated during
* iteration
* @since 2.2
*/
@Repeatable
@Projection
Stream memoize();
// TODO
// /**
// * Memoizes the given
// * number of initial stream elements and their order, by answering a lazy
// * stream with {@link Repeatable} iteration order up to position
// * {@code numberOfElements - 1}
// *
// *
// * @param numberOfElements
// * the number of initial elements to memoize. If this number is
// * greather than stream size, all stream elements are memoized
// * @return a new {@link Stream} that memoizes the first
// * {@code numberOfElements} elements evaluated during iteration
// * @since 2.3
// */
// Stream memoize(int numberOfElements);
/**
* Forces stream elements evaluation by converting it into a new ordered
* stream one that is not lazy and that has repeatable iteration order.
*
* @return a new {@link Stream} that retrieves elements from the next
* iteration of this Stream.
*/
@NonNull
@Repeatable
Stream force();
// Interscalating
/**
* Inserts the given element
between each retrieved element of
* this {@link Stream}
*
* @param element
* @return a new {@link Stream}
*/
@Projection
Stream intersperse(A element);
/**
* Inserts after each element the result of applying the given function to it.
* For example:
*
*
* Streams.cons(10, 9, 90).incorporate(integer().negate()).equiv(10, -10, 9, -9, 90, -90);
*
*
* @param function
* @return a new {@link Stream}
* @since 1.2
*/
@Projection
Stream incorporate(@NonNull Function super A, ? extends A> function);
/**
* Inserts the given value after each element of the stream.
*
* This message is similar to {@link #intersperse(Object)}, but inserts the
* value also at the end of the stream.
*
* @param element
* Example:
*
*
* Streams.cons('a', 'b', 'c').incorporate('d').equiv('a', 'd', 'b', 'd', 'c', 'd');
*
*
* @return a new {@link Stream}
* @since 1.2
*/
@Projection
Stream incorporate(@NonNull A element);
// Grouping
/**
* Groups elements by the given {@code groupingFunction}, and reduces each
* group using the given {@code reduction}.
*
* The grouping is performed so that two elements {@code a} and {@code b} will
* be put in the same group if and only if
* {@code groupFunction.apply(a).equals(groupFunction.apply(b)) }
*
*
* @param
* @param groupFunction
* @param reduction
* @return a Map with an entry for each group, where its key is the result of
* the grouping function, and the value is the result of the reduction
* of the elements for that group
*/
@NonNull
Map groupOn(Applicable super A, K> groupFunction, Reduction reduction);
// Cartesian product
/**
* Answers the Cartesian product of this stream and itself
*
* @param other
* @return a new {@link Stream} projection
* @see Iterables#cross(Iterable, Iterable)
*/
@Projection
Stream> cross();
/**
* Answers the Cartesian product of this stream and the given one
*
* @param
* @param other
* @return a new {@link Stream} projection
* @see Iterables#cross(Iterable, Iterable)
*/
@Projection
Stream> cross(@NonNull Stream other);
/**
* Answers the cartesian product of this {@link Stream} and the given
* {@link Iterable}
*
* @param
* @param other
* @return cross(Streams.from(other))
* @see #cross(Stream)
*/
@Projection
Stream> cross(@NonNull Iterable other);
/**
* Answers the cartesian product of this {@link Stream} and the given
* elements
.
*
* Example:
*
*
* //Answers true
* Streams
* .cons("male", "female")
* .cross("young", "middle-aged", "old")
* .equiv(
* _("male", "young"),
* _("male", "middle-aged"),
* _("male", "old"),
* _("female", "young"),
* _("female", "middle-aged"),
* _("female", "old"));
*
*
*
* @param
* @param other
* @return cross(Streams.cons(elements))
* @see #cross(Stream)
* @since 2.2
*/
Stream> cross(@NonNull B... elements);
/**
* Answers the cartesian product of this {@link Stream} and the given
* {@link Iterator}
*
* @param
* @param other
* @return cross(Streams.from(other))
* @see #cross(Stream)
* @since 2.2
*/
@Projection
Stream> cross(@NonNull Iterator other);
/**
* Answers the cartesian product of this {@link Stream} and each one of the
* given streamOfStreams
*
* @param streamOfStreams
* @return a new {@link Stream} projection
*/
@Projection
Stream> crossStreams(@NonNull Stream> streamOfStreams);
// Transforming whole stream
/**
* Lazily applies the given function to this {@link Stream}.
*
* @param
* @param function
* the function to apply to this stream
* @return a new stream that will retrieve elements from the result of
* applying the given function to this stream
*/
@Projection
Stream transform(@NonNull Applicable, ? extends Stream> function);
/**
* Lazily applies the given function
to this stream,
* deconstructing this stream into head and tail, or into an empty stream.
*
* Unlike {@link Stream#transform(Applicable)}, whose function will receive
* the whole stream, the given {@link DeconsApplicable}, when applied, will
* take the head and tail of this {@link Stream}, if non empty, or no
* arguments, if the stream is empty.
*
* @param
* @param function
* @return a new stream that will retrieve elements from the result of
* applying the given function to this stream
* @see #decons()
*/
@Projection
Stream transform(@NonNull DeconsApplicable function);
/**
* Lazily applies the given function
to this stream,
* deconstructing this stream into a head thunk and tail, or into an empty
* stream.
*
* Unlike {@link Stream#transform(Applicable)}, whose function will receive
* the whole stream, the given {@link DeconsApplicable}, when applied, will
* take a head's thunk and tail of this {@link Stream}, if non empty, or no
* arguments, if the stream is empty.
*
* @param
* @param function
* @return a new stream that will retrieve elements from the result of
* applying the given function to this stream
* @see #delayedDecons()
*/
@Projection
Stream transform(@NonNull DelayedDeconsApplicable function);
// Accessing elements in ordered manner
/**
* Answers the first element.
*
* This is equivalent to {@link Stream#head()}.
*
* It is also equivalent to {@code get(0)}, but throws a
* {@link EmptySourceException} if stream is empty
*
* @return {@link #head()}
* @throws EmptySourceException
* if there is no first element
*/
A first() throws EmptySourceException;
/**
* Answers the second element. This is equivalent to {@code get(1)}, but
* throws a {@link NoSuchElementException} if stream {@code size < 2}
*
* @return {@code get(1)}
* @throws NoSuchElementException
* if there is no second element
*/
A second() throws NoSuchElementException;
/**
* Answers the third element. This is equivalent to {@code get(2)}, but throws
* a {@link NoSuchElementException} if stream {@code size < 3}
*
* @return {@code get(2)}
* @throws IndexOutOfBoundsException
* if there is no third element
*/
A third() throws NoSuchElementException;
/**
* Answers the last element of this stream. This method only works with finite
* streams
*
* @return the last element
* @throws EmptySourceException
*/
A last() throws EmptySourceException;
/**
* Answers if both arguments are contained by this stream, and the first one
* is before the second one. This method works even for stream that can be
* iterated only once
*
* @param previous
* @param next
* @return whether both elements are contained by this {@link Stream}, and the
* first is before the second one.
* @see #containsBefore(Object, Object)
*/
boolean isBefore(A previous, A next);
/**
* Answers if {@code element} is contained by this stream, and its first
* occurence is before the first occurence of the second one, if any.
*
*
* This message is similar to {@link #isBefore(Object, Object)}, but may be
* true even if the {@code reference} is not present at the stream. It will be
* always true
if both element and reference are equal, too.
*
* Examples:
*
*
* Streams.from("abcd").containsBefore('c', 'a'); //false. c is after a
* Streams.from("abcd").containsBefore('x', 'd'); //false. x is not present
* Streams.from("abcd").containsBefore('a', 'b'); //true
* Streams.from("abcd").containsBefore('b', 'd'); //true
* Streams.from("abcd").containsBefore('a', 'a'); //true
* Streams.from("abcd").containsBefore('x', 'x'); //false. x is not present
*
*
* @param element
* the element to test whether it is contained by this stream, and
* appears before {@code reference}
* @param reference
* @return whether both elements are contained by this {@link Stream}, and the
* first is before the second one.
* @see #insertBefore(Object, Object)
* @see #isBefore(Object, Object)
* @since 2.2
*/
boolean containsBefore(A element, A reference);
/**
* Answers if {@code element} is contained by this stream, and its first
* occurence is before the given {@code index}.
*
* As a particular case, if {@code index} is 0, return always
* false
*
* Examples:
*
*
* Streams.from("abcd").containsBeforeIndex('x', 2); //false. x is not present
* Streams.from("abcd").containsBeforeIndex('c', 1); //false. c is present but at index 2
* Streams.from("abcd").containsBeforeIndex('a', 0); //false. a is present but at index 0
* Streams.from("abcd").containsBeforeIndex('a', 1); //true
* Streams.from("abcd").containsBeforeIndex('b', 3); //true
* Streams.from("abcd").containsBeforeIndex('b', 40); //true
*
*
* @param element
* @param index
* @return whether elements is containted and before index
* @since 2.2
* @see #insertBeforeIndex(Object, int)
*/
boolean containsBeforeIndex(A element, @NotNegative int index);
/**
* Answers the n-th element.
*
* @param n
* @return the n-th element, zero based
* @throws IndexOutOfBoundsException
* if there is no n-th element, because stream has less than {@code n} elements
*/
A get(int n);
/**
* Answers the zero-based index of the given element
*
* @param element
* @return the index of the element first element equal to {@code element}, or
* -1, if it is not contained by this stream
*/
int indexOf(A element);
/**
* Answers the zero-based index of first element that matches the given
* predicate
*
* @param predicate
* @return the index of the first element that evaluates the {@code predicate}
* to true, or -1, if no element satisfies it
* @since 2.1
*/
int findIndex(Evaluable super A> predicate);
/**
* Answers a stream containing all the zero-based indices of the elements that
* matches the given predicate
*
* @param predicate
* @return a {@link Stream} with the indices of the elements that satisfy the
* given predicate
* @since 2.1
*/
@Projection
Stream indices(Evaluable super A> predicate);
/**
* Answers the index of the given present element. This
* method behaves exactly like {@link #indexOf(Object)}, with the only
* difference that it will throw a {@link NoSuchElementException} if the given
* element is not present on the stream
*
* @param element
* @return the index of the given element
* @throws NoSuchElementException
* if the element is no contained by this {@link Stream}
*/
int positionOf(A element) throws NoSuchElementException;
/**
* Answers the zero-based index of first, present element
* that matches the given predicate. This method behaves exactly like
* {@link #findIndex(Evaluable)}, with the only difference that it will throw
* a {@link NoSuchElementException} if the given element is not present on the
* stream
*
* @param predicate
* @return the index of the first element that evaluates the {@code predicate}
* @throws NoSuchElementException
* if no elements satisfies the given {@code predicate}
* @since 2.1
*/
int findPosition(Evaluable super A> predicate) throws NoSuchElementException;
/**
* Preserves elements that whose index satisfy the given
* predicate
*
* @param predicate
* @return a new {@link Stream} projection that will retrieve only elements
* whose index evaluate to true
*/
@Projection
Stream filterIndex(@NonNull Evaluable predicate);
/**
* Answers a streams that retrieves all the elements of this one, except of
* that at the given index
*
* @param predicate
* @return a new {@link Stream} that skips the element at the given index
*/
@Projection
Stream skipIndex(int index);
/*Deconstructtion */
/**
* Answers this stream split into head and tail.
*
* This method is preferred over {@link #head()} and {@link #tail()}, as it
* will work as expected even on non repeatable iteration streams.
*
* @return a pair containing the head and the tail of this stream. The tail is
* {@link NonNull} and a {@link Projection}, but it is always
* non-repeatable.
* @throws EmptySourceException
* if stream is empty
*/
@NonNull
Tuple2> decons() throws EmptySourceException;
/**
* Answers this non-empty stream split into a head thunk and tail.
*
* This method is preferred over {@link #decons()} when the head value of the
* {@link Stream} is potentially irrelevant, as this methods grants to suceeds
* even in those cases where {@link #head()} fails.
*
* @return a pair containing a thunk that will provide the head, and the tail
* of this stream. The tail is {@link NonNull} and a
* {@link Projection}, but it is always non-repeatable.
* @throws EmptySourceException
* if stream is empty
*/
@NonNull
Tuple2, Stream> delayedDecons() throws EmptySourceException;
/**
* Answers the head of the {@link Stream}, which is the first element of the
* stream. However, if you need both head and tail in order to perfom
* functional-style transformations over the stream, consider using
* {@link #decons()}.
*
* @return {@link Stream#first()}
* @throws EmptySourceException
* if stream is empty
*/
A head() throws EmptySourceException;
/**
* Answers the tail of the {@link Stream}
*
* @return an {@link Stream} that retrieves all its elements, except of the
* first one
* @throws EmptySourceException
* if stream is empty
*/
@Projection
Stream tail() throws EmptySourceException;
/**
* @author flbulgarelli
* @param
*/
public interface EmptyApplicable {
/**
* Applies this transformation when this Stream can not be deconstructed in
* head and tail, because it is empty.
*
* @return the result of applying this transformation over and empty
* {@link Stream}
*/
A emptyApply();
}
/**
* An {@link Applicable2} that can transform a {@link Stream} by
* deconstructing it into head and tail, or into an empty stream.
*
* @author flbulgarelli
*
* @param
* input stream type
* @param
* output stream type
*/
public interface DeconsApplicable extends Applicable2, Stream>, EmptyApplicable> {
/**
* Applies this transformation to a non empty Stream splitted into tail and
* head.
*
* Independently of the original stream source, the tail Stream is always
* non-repeatable.
*
* {@link Stream}s will send this message when evaluating
* {@link Stream#transform(DeconsApplicable)}
*/
Stream apply(A head, Stream tail);
}
/**
* An {@link Applicable2} that can transform a {@link Stream} by
* deconstructing it into head thunk and tail, or into an empty stream.
*
* @author flbulgarelli
*
* @param
* input stream type
* @param
* output stream type
*/
public interface DelayedDeconsApplicable extends Applicable2, Stream, Stream>,
EmptyApplicable> {
/**
* Applies this transformation to a non empty Stream splitted into tail and
* head's thunk.
*
* Independently of the original stream source, the tail Stream is always
* non-repeatable.
*
* {@link Stream}s will send this message when evaluating
* {@link Stream#transform(DeconsApplicable)}
*/
Stream apply(Thunk head, Stream tail);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy