Mercurial > hg > openjdk > lambda > jdk
changeset 7541:e27acedff205
First go at docs on Streams and lazy/non-lazy spliterators of sources.
author | psandoz |
---|---|
date | Wed, 27 Feb 2013 17:46:27 +0100 |
parents | 9619ab4afc70 |
children | b3e0b5001b69 |
files | src/share/classes/java/util/stream/Streams.java src/share/classes/java/util/stream/package-info.java |
diffstat | 2 files changed, 414 insertions(+), 24 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/java/util/stream/Streams.java Wed Feb 27 12:16:39 2013 +0100 +++ b/src/share/classes/java/util/stream/Streams.java Wed Feb 27 17:46:27 2013 +0100 @@ -40,124 +40,345 @@ import java.util.function.UnaryOperator; /** - * Streams + * This class contains various methods that operate on and/or return instances of {@link Stream}, + * as well as the primitive specializations {@link IntStream}, {@link LongStream}, and {@link DoubleStream}. * * @since 1.8 */ -public class Streams { +public final class Streams { private Streams() { throw new Error("no instances"); } - public static final long MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; + /** + * The maximum size of array to allocate. + */ + static final long MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // Stream construction + /** + * Creates an empty stream. + * + * @param <T> Type of elements + * @return An empty stream + */ public static<T> Stream<T> emptyStream() { return stream(Spliterators.<T>emptySpliterator()); } + /** + * Creates a new sequential stream whose source is a {@code Supplier} of a non-lazy {@code Spliterator}. + * <p> + * The non-lazy {@code Spliterator} is obtained from the {@code Supplier} when the terminal operation of the stream + * pipeline commences. See <a href="package-summary.html#StreamSources">Stream sources</a> for more details. + * + * @param source A {@code Supplier} of a {@code Spliterator} + * @param characteristics Characteristics of the supplied {@code Spliterator}. The characteristics + * must be equal to {@code source.get().getCharacteristics()} + * @param <T> Type of elements + * @return A new stream + */ public static<T> Stream<T> stream(Supplier<? extends Spliterator<T>> source, int characteristics) { Objects.requireNonNull(source); return new ReferencePipeline<>(source, StreamOpFlag.fromCharacteristics(characteristics) & ~StreamOpFlag.IS_PARALLEL); } + /** + * Creates a new parallel stream whose source is a {@code Supplier} of a non-lazy {@code Spliterator}. + * <p> + * The non-lazy {@code Spliterator} is obtained from the {@code Supplier} when the terminal operation of the stream + * pipeline commences. See <a href="package-summary.html#StreamSources">Stream sources</a> for more details. + * + * @param source A {@code Supplier} of a {@code Spliterator} + * @param characteristics Characteristics of the supplied {@code Spliterator}. The characteristics + * must be equal to {@code source.get().getCharacteristics()} + * @param <T> Type of elements + * @return A new stream + */ public static<T> Stream<T> parallelStream(Supplier<? extends Spliterator<T>> source, int characteristics) { Objects.requireNonNull(source); return new ReferencePipeline<>(source, StreamOpFlag.fromCharacteristics(characteristics) | StreamOpFlag.IS_PARALLEL); } + /** + * Creates a new sequential stream whose source is a lazy {@code Spliterator}. + * <p> + * The {@code Spliterator} must be <b>lazy</b> and not commit to the sequence of elements it covers until it is + * invoked with a method that requires the sequence of elements be known, for example when the size estimate is + * required or when traversal occurs, but not when the characteristics are required. See + * <a href="package-summary.html#StreamSources">Stream sources</a> for more details. + * + * @param source A {@code Spliterator} + * @param <T> Type of elements + * @return A new stream + */ public static<T> Stream<T> stream(Spliterator<T> source) { return stream(() -> source, source.characteristics()); } + /** + * Creates a new parallel stream whose source is a lazy {@code Spliterator}. + * <p> + * The {@code Spliterator} must be <b>lazy</b> and not commit to the sequence of elements it covers until it is + * invoked with a method that requires the sequence of elements be known, for example when the size estimate is + * required or when traversal occurs, but not when the characteristics are required. See + * <a href="package-summary.html#StreamSources">Stream sources</a> for more details. + * + * @param source A {@code Spliterator} + * @param <T> Type of elements + * @return A new stream + */ public static<T> Stream<T> parallelStream(Spliterator<T> source) { return parallelStream(() -> source, source.characteristics()); } // IntStream construction + /** + * Creates an empty {@code int} stream. + * + * @return An empty {@code int} stream + */ public static IntStream emptyIntStream() { return intStream(Spliterators.emptyIntSpliterator()); } + /** + * Creates a new sequential {@code int} stream whose source is a {@code Supplier} of a non-lazy + * {@code Spliterator.OfInt}. + * <p> + * The non-lazy {@code Spliterator.OfInt} is obtained from the {@code Supplier} when the terminal operation of the + * stream pipeline commences. See <a href="package-summary.html#StreamSources">Stream sources</a> for more details. + * + * @param source A {@code Supplier} of a {@code Spliterator.OfInt} + * @param characteristics Characteristics of the supplied {@code Spliterator.OfInt}. The characteristics + * must be equal to {@code source.get().getCharacteristics()} + * @return A new {@code int} stream + */ public static IntStream intStream(Supplier<? extends Spliterator.OfInt> source, int characteristics) { return new IntPipeline<>(source, StreamOpFlag.fromCharacteristics(characteristics) & ~StreamOpFlag.IS_PARALLEL); } + /** + * Creates a new parallel {@code int} stream whose source is a {@code Supplier} of a non-lazy + * {@code Spliterator.OfInt}. + * <p> + * The non-lazy {@code Spliterator.OfInt} is obtained from the {@code Supplier} when the terminal operation of the + * stream pipeline commences. See <a href="package-summary.html#StreamSources">Stream sources</a> for more details. + * + * @param source A {@code Supplier} of a {@code Spliterator.OfInt} + * @param characteristics Characteristics of the supplied {@code Spliterator.OfInt}. The characteristics + * must be equal to {@code source.get().getCharacteristics()} + * @return A new {@code int} stream + */ public static IntStream intParallelStream(Supplier<? extends Spliterator.OfInt> source, int characteristics) { return new IntPipeline<>(source, StreamOpFlag.fromCharacteristics(characteristics) | StreamOpFlag.IS_PARALLEL); } + /** + * Creates a new sequential {@code int} stream whose source is a lazy {@code Spliterator.OfInt}. + * <p> + * The {@code Spliterator.OfInt} must be <b>lazy</b> and not commit to the sequence of elements it covers until it + * is invoked with a method that requires the sequence of elements be known, for example when the size estimate is + * required or when traversal occurs, but not when the characteristics are required. See + * <a href="package-summary.html#StreamSources">Stream sources</a> for more details. + * + * @param source A {@code Spliterator.OfInt} + * @return A new {@code int} stream + */ public static IntStream intStream(Spliterator.OfInt source) { return intStream(() -> source, source.characteristics()); } + /** + * Creates a new parallel {@code int} stream whose source is a lazy {@code Spliterator.OfInt}. + * <p> + * The {@code Spliterator.OfInt} must be <b>lazy</b> and not commit to the sequence of elements it covers until it + * is invoked with a method that requires the sequence of elements be known, for example when the size estimate is + * required or when traversal occurs, but not when the characteristics are required. See + * <a href="package-summary.html#StreamSources">Stream sources</a> for more details. + * + * @param source A {@code Spliterator.OfInt} + * @return A new {@code int} stream + */ public static IntStream intParallelStream(Spliterator.OfInt source) { return intParallelStream(() -> source, source.characteristics()); } // LongStream construction + /** + * Creates an empty {@code long} stream. + * + * @return An empty {@code long} stream + */ public static LongStream emptyLongStream() { return longStream(Spliterators.emptyLongSpliterator()); } + /** + * Creates a new sequential {@code long} stream whose source is a {@code Supplier} of a non-lazy + * {@code Spliterator.OfLong}. + * <p> + * The non-lazy {@code Spliterator.OfLong} is obtained from the {@code Supplier} when the terminal operation of the + * stream pipeline commences. See <a href="package-summary.html#StreamSources">Stream sources</a> for more details. + * + * @param source A {@code Supplier} of a {@code Spliterator.OfLong} + * @param characteristics Characteristics of the supplied {@code Spliterator.OfLong}. The characteristics + * must be equal to {@code source.get().getCharacteristics()} + * @return A new {@code long} stream + */ public static LongStream longStream(Supplier<? extends Spliterator.OfLong> source, int characteristics) { return new LongPipeline<>(source, StreamOpFlag.fromCharacteristics(characteristics) & ~StreamOpFlag.IS_PARALLEL); } + /** + * Creates a new parallel {@code long} stream whose source is a {@code Supplier} of a non-lazy + * {@code Spliterator.OfLong}. + * <p> + * The non-lazy {@code Spliterator.OfLong} is obtained from the {@code Supplier} when the terminal operation of the + * stream pipeline commences. See <a href="package-summary.html#StreamSources">Stream sources</a> for more details. + * + * @param source A {@code Supplier} of a {@code Spliterator.OfLong} + * @param characteristics Characteristics of the supplied {@code Spliterator.OfLong}. The characteristics + * must be equal to {@code source.get().getCharacteristics()} + * @return A new {@code long} stream + */ public static LongStream longParallelStream(Supplier<? extends Spliterator.OfLong> source, int characteristics) { return new LongPipeline<>(source, StreamOpFlag.fromCharacteristics(characteristics) | StreamOpFlag.IS_PARALLEL); } + /** + * Creates a new sequential {@code long} stream whose source is a lazy {@code Spliterator.OfLong}. + * <p> + * The {@code Spliterator.OfLong} must be <b>lazy</b> and not commit to the sequence of elements it covers until it + * is invoked with a method that requires the sequence of elements be known, for example when the size estimate is + * required or when traversal occurs, but not when the characteristics are required. See + * <a href="package-summary.html#StreamSources">Stream sources</a> for more details. + * + * @param source A {@code Spliterator.OfLong} + * @return A new {@code long} stream + */ public static LongStream longStream(Spliterator.OfLong source) { return longStream(() -> source, source.characteristics()); } + /** + * Creates a new parallel {@code long} stream whose source is a lazy {@code Spliterator.OfLong}. + * <p> + * The {@code Spliterator.OfLong} must be <b>lazy</b> and not commit to the sequence of elements it covers until it + * is invoked with a method that requires the sequence of elements be known, for example when the size estimate is + * required or when traversal occurs, but not when the characteristics are required. See + * <a href="package-summary.html#StreamSources">Stream sources</a> for more details. + * + * @param source A {@code Spliterator.OfLong} + * @return A new {@code long} stream + */ public static LongStream longParallelStream(Spliterator.OfLong source) { return longParallelStream(() -> source, source.characteristics()); } // DoubleStream construction + /** + * Creates an empty {@code double} stream. + * + * @return An empty {@code double} stream + */ public static DoubleStream emptyDoubleStream() { return doubleStream(Spliterators.emptyDoubleSpliterator()); } - public static DoubleStream doubleStream(Supplier<? extends Spliterator.OfDouble> source, int characteristics) { + /** + * Creates a new sequential {@code double} stream whose source is a {@code Supplier} of a non-lazy + * {@code Spliterator.OfDouble}. + * <p> + * The non-lazy {@code Spliterator.OfDouble} is obtained from the {@code Supplier} when the terminal operation of + * the stream pipeline commences. See <a href="package-summary.html#StreamSources">Stream sources</a> for more + * details. + * + * @param source A {@code Supplier} of a {@code Spliterator.OfDouble} + * @param characteristics Characteristics of the supplied {@code Spliterator.OfDouble}. The characteristics + * must be equal to {@code source.get().getCharacteristics()} + * @return A new {@code double} stream + */ + public static DoubleStream doubleStream(Supplier<? extends Spliterator.OfDouble> source, + int characteristics) { return new DoublePipeline<>(source, StreamOpFlag.fromCharacteristics(characteristics) & ~StreamOpFlag.IS_PARALLEL); } - public static DoubleStream doubleParallelStream(Supplier<? extends Spliterator.OfDouble> source, int characteristics) { + /** + * Creates a new parallel {@code double} stream whose source is a {@code Supplier} of a non-lazy + * {@code Spliterator.OfDouble}. + * <p> + * The non-lazy {@code Spliterator.OfDouble} is obtained from the {@code Supplier} when the terminal operation of + * the stream pipeline commences. See <a href="package-summary.html#StreamSources">Stream sources</a> for more + * details. + * + * @param source A {@code Supplier} of a {@code Spliterator.OfDouble} + * @param characteristics Characteristics of the supplied {@code Spliterator.OfDouble}. The characteristics + * must be equal to {@code source.get().getCharacteristics()} + * @return A new {@code double} stream + */ + public static DoubleStream doubleParallelStream(Supplier<? extends Spliterator.OfDouble> source, + int characteristics) { return new DoublePipeline<>(source, StreamOpFlag.fromCharacteristics(characteristics) | StreamOpFlag.IS_PARALLEL); } + /** + * Creates a new sequential {@code double} stream whose source is a lazy {@code Spliterator.OfDouble}. + * <p> + * The {@code Spliterator.OfDouble} must be <b>lazy</b> and not commit to the sequence of elements it covers until + * it is invoked with a method that requires the sequence of elements be known, for example when the size estimate + * is required or when traversal occurs, but not when the characteristics are required. See + * <a href="package-summary.html#StreamSources">Stream sources</a> for more details. + * + * @param source A {@code Spliterator.OfDouble} + * @return A new {@code double} stream + */ public static DoubleStream doubleStream(Spliterator.OfDouble source) { return doubleStream(() -> source, source.characteristics()); } + /** + * Creates a new parallel {@code double} stream whose source is a lazy {@code Spliterator.OfDouble}. + * <p> + * The {@code Spliterator.OfDouble} must be <b>lazy</b> and not commit to the sequence of elements it covers until + * it is invoked with a method that requires the sequence of elements be known, for example when the size estimate + * is required or when traversal occurs, but not when the characteristics are required. See + * <a href="package-summary.html#StreamSources">Stream sources</a> for more details. + * + * @param source A {@code Spliterator.OfDouble} + * @return A new {@code double} stream + */ public static DoubleStream doubleParallelStream(Spliterator.OfDouble source) { return doubleParallelStream(() -> source, source.characteristics()); } - // Empty iterators and spliterators - - // Iterators from spliterators + // Infinite Stream generators - // Spliterators from iterators - - // Infinite stream generators - + /** + * Creates a sequential stream that is an infinite sequence of elements. The first element is {@code seed}, the + * second element is the result of applying {@code seed} to the function {@code f}, and the nth element is the + * result of applying the nth minus one element to the function {@code f}. + * <p> + * To transform into a parallel stream call the {@code parallel()} method on the created stream. + * + * @param seed The first element in sequence + * @param f The function to be applied to the nth minus one element to produce the nth element, where n > 1 + * @param <T> The type of elements + * @return A stream that is an infinite sequence of elements + */ public static<T> Stream<T> iterate(final T seed, final UnaryOperator<T> f) { Objects.requireNonNull(f); final InfiniteIterator<T> iterator = new InfiniteIterator<T>() { @@ -171,11 +392,38 @@ return stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED)); } - public static<T> Stream<T> generate(Supplier<T> f) { - InfiniteIterator<T> iterator = f::get; + /** + * Creates a sequential stream that is an infinite sequence of supplied elements. Each element is supplied in + * sequence order. + * <p> + * A {@code Supplier} can supply constant values, such as {@code () -> "CONSTANT"}, or can supply non-constant + * values in which case the {@code Supplier} may have side-effects. + * <p> + * To transform into a parallel stream call the {@code parallel()} method on the created stream. + * + * @param s the {@code Supplier} of elements; may have side-effects. The {@code Supplier} will not be invoked + * concurrently so it need not protect access to mutable state. + * @param <T> The type of elements + * @return A stream that is an infinite sequence of elements + */ + public static<T> Stream<T> generate(Supplier<T> s) { + InfiniteIterator<T> iterator = s::get; return stream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED)); } + // Infinite IntStream generators and ranges + + /** + * Creates a sequential {@code int} stream that is an infinite sequence of {@code int} elements. The first element + * is {@code seed}, the second element is the result of applying {@code seed} to the function {@code f}, and the + * nth element is the result of applying the nth minus one element to the function {@code f}. + * <p> + * To transform into a parallel stream call the {@code parallel()} method on the created stream. + * + * @param seed The first {@code int} element in sequence + * @param f The function to be applied to the nth minus one element to produce the nth element, where n > 1 + * @return An {@code int} stream that is an infinite sequence of {@code int} elements + */ public static IntStream iterateInt(final int seed, final IntUnaryOperator f) { Objects.requireNonNull(f); final InfiniteIterator.OfInt iterator = new InfiniteIterator.OfInt() { @@ -191,8 +439,21 @@ return intStream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED)); } - public static IntStream generateInt(IntSupplier f) { - InfiniteIterator.OfInt iterator = f::getAsInt; + /** + * Creates a sequential {@code int} stream that is an infinite sequence of supplied {@code int} elements. Each + * element is supplied in sequence order. + * <p> + * A {@code IntSupplier} can supply constant values, such as {@code () -> 123}, or can supply non-constant + * values in which case the {@code IntSupplier} may have side-effects. + * <p> + * To transform into a parallel stream call the {@code parallel()} method on the created stream. + * + * @param s the {@code IntSupplier} of elements; may have side-effects. The {@code IntSupplier} will not be invoked + * concurrently so it need not protect access to mutable state. + * @return An {@code int} stream that is an infinite sequence of {@code int} elements + */ + public static IntStream generateInt(IntSupplier s) { + InfiniteIterator.OfInt iterator = s::getAsInt; return intStream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED)); } @@ -254,6 +515,19 @@ return intStream(new RangeIntSpliterator(start, end, step)); } + // Infinite LongStream generators and ranges + + /** + * Creates a sequential {@code long} stream that is an infinite sequence of {@code long} elements. The first + * element is {@code seed}, the second element is the result of applying {@code seed} to the function {@code f}, and + * the nth element is the result of applying the nth minus one element to the function {@code f}. + * <p> + * To transform into a parallel stream call the {@code parallel()} method on the created stream. + * + * @param seed The first {@code long} element in sequence + * @param f The function to be applied to the nth minus one element to produce the nth element, where n > 1 + * @return A {@code long} stream that is an infinite sequence of {@code long} elements + */ public static LongStream iterateLong(final long seed, final LongUnaryOperator f) { Objects.requireNonNull(f); final InfiniteIterator.OfLong iterator = new InfiniteIterator.OfLong() { @@ -269,8 +543,21 @@ return longStream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED)); } - public static LongStream generateLong(LongSupplier f) { - InfiniteIterator.OfLong iterator = f::getAsLong; + /** + * Creates a sequential {@code long} stream that is an infinite sequence of supplied {@code long} elements. Each + * element is supplied in sequence order. + * <p> + * A {@code LongSupplier} can supply constant values, such as {@code () -> 123L}, or can supply non-constant + * values in which case the {@code LongSupplier} may have side-effects. + * <p> + * To transform into a parallel stream call the {@code parallel()} method on the created stream. + * + * @param s the {@code LongSupplier} of elements; may have side-effects. The {@code LongSupplier} will not be + * invoked concurrently so it need not protect access to mutable state. + * @return A {@code long} stream that is an infinite sequence of {@code long} elements + */ + public static LongStream generateLong(LongSupplier s) { + InfiniteIterator.OfLong iterator = s::getAsLong; return longStream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED)); } @@ -332,6 +619,19 @@ return longStream(new RangeLongSpliterator(start, end, step)); } + // Infinite DoubleStream generators + + /** + * Creates a sequential {@code double} stream that is an infinite sequence of {@code double} elements. The first + * element is {@code seed}, the second element is the result of applying {@code seed} to the function {@code f}, and + * the nth element is the result of applying the nth minus one element to the function {@code f}. + * <p> + * To transform into a parallel stream call the {@code parallel()} method on the created stream. + * + * @param seed The first {@code double} element in sequence + * @param f The function to be applied to the nth minus one element to produce the nth element, where n > 1 + * @return A {@code double} stream that is an infinite sequence of {@code double} elements + */ public static DoubleStream iterateDouble(final double seed, final DoubleUnaryOperator f) { Objects.requireNonNull(f); final InfiniteIterator.OfDouble iterator = new InfiniteIterator.OfDouble() { @@ -347,13 +647,39 @@ return doubleStream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED)); } - public static DoubleStream generateDouble(DoubleSupplier f) { - InfiniteIterator.OfDouble iterator = f::getAsDouble; + /** + * Creates a sequential {@code double} stream that is an infinite sequence of supplied {@code double} elements. + * Each element is supplied in sequence order. + * <p> + * A {@code DoubleSupplier} can supply constant values, such as {@code () -> 123.0}, or can supply non-constant + * values in which case the {@code DoubleSupplier} may have side-effects. + * <p> + * To transform into a parallel stream call the {@code parallel()} method on the created stream. + * + * @param s the {@code DoubleSupplier} of elements; may have side-effects. The {@code DoubleSupplier} will not be + * invoked concurrently so it need not protect access to mutable state. + * @return A {@code double} stream that is an infinite sequence of {@code double} elements + */ + public static DoubleStream generateDouble(DoubleSupplier s) { + InfiniteIterator.OfDouble iterator = s::getAsDouble; return doubleStream(Spliterators.spliteratorUnknownSize(iterator, Spliterator.ORDERED)); } - // Concat + // Stream combining functions + /** + * Creates a concatenated stream whose elements are all the elements, in encounter order if any, of a first stream + * proceeded by all the elements of a second stream, in encounter order if any. + * <p> + * The concatenated stream is lazy and elements are not consumed until the terminal operation is executed. + * <p> + * To transform into a parallel stream call the {@code parallel()} method on the created stream. + * + * @param a The first stream + * @param b The second stream to concatenate on to end of the first stream + * @param <T> Type of elements + * @return A concatenated stream + */ public static<T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b) { @SuppressWarnings("unchecked") Spliterator<T> aSpliterator = (Spliterator<T>) Objects.requireNonNull(a).spliterator(); @@ -433,6 +759,29 @@ : stream(split); } + /** + * + * Creates a zipped stream whose elements are the result of combining the elements of two streams, in encounter + * order if any. + * <p> + * The number of elements of the zipped stream will be the smaller of the number of elements of the first or second + * stream. + * <p> + * The zipped stream is lazy and elements are not consumed until the terminal operation is executed. If one stream + * is larger than the other then only some of the elements of the larger stream will be consumed, at most the number + * of elements consumed will be the same as the total number of elements of the smaller stream. + * <p> + * To transform into a parallel stream call the {@code parallel()} method on the created stream. + * + * @param a The first stream to combine + * @param b The second stream to combine + * @param zipper The function applied to an element from the first stream and an element from the second stream + * to produce an element for the zipped stream + * @param <A> The type of elements of the first stream + * @param <B> The type of elements of the second stream + * @param <C> The type of elements of the zipped stream + * @return A zipped stream + */ public static<A, B, C> Stream<C> zip(Stream<? extends A> a, Stream<? extends B> b, BiFunction<? super A, ? super B, ? extends C> zipper) { @@ -474,7 +823,7 @@ : stream(split); } - // Spliterator implementations + // Iterator and Spliterator implementations private interface InfiniteIterator<T> extends Iterator<T> { /** Always returns true */ @@ -490,7 +839,7 @@ interface OfDouble extends InfiniteIterator<Double>, PrimitiveIterator.OfDouble { } } - private static class RangeIntSpliterator implements Spliterator.OfInt { + private static final class RangeIntSpliterator implements Spliterator.OfInt { private int from; private final int upTo; private final int step; @@ -555,7 +904,7 @@ } } - private static class RangeLongSpliterator implements Spliterator.OfLong { + private static final class RangeLongSpliterator implements Spliterator.OfLong { private long from; private final long upTo; private final long step;
--- a/src/share/classes/java/util/stream/package-info.java Wed Feb 27 12:16:39 2013 +0100 +++ b/src/share/classes/java/util/stream/package-info.java Wed Feb 27 17:46:27 2013 +0100 @@ -76,6 +76,47 @@ * <p>Terminal operations consume the {@code Stream} and produce a result or a side-effect. After a terminal * operation is performed, the stream can no longer be used. * + * <h3><a name="StreamSources">Stream sources</a></h3> + * + * <p>A pipeline is initially constructed from a stream source. A stream source supplies a {@code Spliterator} that + * covers elements of the source and provides element traversal operations for a possibly-parallel computation. The + * {@code Spliterator} is used to construct the initial {@code Stream} in the pipeline. See methods on + * {@link java.util.stream.Streams} for such construction. + * + * <p>A source may directly supply a {@code Spliterator}. If so, that {@code Spliterator} must be <b>lazy</b> and not + * commit to the sequence of elements it covers until the terminal operation commences. More specifically the + * {@code Spliterator} must not commit until it is invoked with a method that requires the sequence of elements be + * known, for example when the size estimate is required or when traversal occurs. + * + * <p>If the contents of the source can be and are modified before the point at which the terminal operation commences + * then those modifications must be reflected in the covered elements. After that point, and depending on the + * properties of the source, modifications might not be reflected in the covered elements and the throwing of a + * {@code ConcurrentModificationException} may occur. + * + * <p>For example, in the following code a list is created consisting of two strings "one" and "two", a stream is + * created from that list, then the list is modified adding a third string "three", finally the elements of the stream + * are collected and joined together. Since the list was modified before the terminal {@code collect} operation + * commenced the result will be a string of "one two three": + * <pre> + * List<String> l = new ArrayList(Arrays.asList("one", "two")); + * Stream<String> sl = l.stream(); + * l.add("three"); + * String s = sl.collect(toStringJoiner(" ")).toString(); + * </pre> + * However, if the list is modified after the terminal operation commences then a + * {@code ConcurrentModificationException} will occur, such as: + * <pre> + * List<String> l = new ArrayList(Arrays.asList("one", "two")); + * Stream<String> sl = l.stream(); + * String s = sl.peek(s -> l.add("BAD LAMBDA")).collect(toStringJoiner(" ")).toString(); + * </pre> + * Note: the lambda expression in the {@code peek} operation is modifying mutable state, see the section on + * <em>Non-interference</em> for further details on the <em>non-interference</em> rules lambda expressions should obey. + * + * <p>If a source cannot directly supply a lazy {@code Spliterator} then it may do so indirectly using a + * {@code Supplier} of a non-lazy {@code Spliterator}. The {@code Spliterator} will be obtained from the + * {@code Supplier} when the terminal operation commences. + * * <h3><a name="StreamOps">Stream operations</a></h3> * * <p>Stream operations are divided into two categories: <em>intermediate</em> and <em>terminal</em>. An