OpenJDK / lambda / lambda / jdk
changeset 7827:c537f01643b4
More package-doc and stream specification
author | briangoetz |
---|---|
date | Fri, 05 Apr 2013 14:44:30 -0400 |
parents | cb2c69a86f0f |
children | 360ebf593040 |
files | src/share/classes/java/nio/file/Files.java src/share/classes/java/util/stream/BaseStream.java src/share/classes/java/util/stream/Stream.java src/share/classes/java/util/stream/package-info.java |
diffstat | 4 files changed, 120 insertions(+), 45 deletions(-) [+] |
line wrap: on
line diff
--- a/src/share/classes/java/nio/file/Files.java Fri Apr 05 10:50:31 2013 -0700 +++ b/src/share/classes/java/nio/file/Files.java Fri Apr 05 14:44:30 2013 -0400 @@ -3220,7 +3220,7 @@ } }; - return new DelegatingCloseableStream(ds, + return new DelegatingCloseableStream<>(ds, Streams.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT))); } @@ -3312,7 +3312,7 @@ } FileTreeIterator itor = FileTreeIterator.iterator(start, maxDepth, options); - return new DelegatingCloseableStream(itor, + return new DelegatingCloseableStream<>(itor, Streams.stream(Spliterators.spliteratorUnknownSize(itor, Spliterator.DISTINCT)) .map(entry -> entry.getPath())); } @@ -3409,7 +3409,7 @@ throw new IllegalArgumentException("'maxDepth' is negative"); } FileTreeIterator itor = FileTreeIterator.iterator(start, maxDepth, options); - return new DelegatingCloseableStream(itor, + return new DelegatingCloseableStream<>(itor, Streams.stream(Spliterators.spliteratorUnknownSize(itor, Spliterator.DISTINCT)) .filter(entry -> matcher.test(entry.getPath(), entry.getFileAttributes())) .map(entry -> entry.getPath())); @@ -3462,6 +3462,6 @@ throws IOException { BufferedReader br = Files.newBufferedReader(path, cs); - return new DelegatingCloseableStream(br, br.lines()); + return new DelegatingCloseableStream<>(br, br.lines()); } }
--- a/src/share/classes/java/util/stream/BaseStream.java Fri Apr 05 10:50:31 2013 -0700 +++ b/src/share/classes/java/util/stream/BaseStream.java Fri Apr 05 14:44:30 2013 -0400 @@ -30,8 +30,8 @@ /** * Base interface for stream types such as {@link Stream}, {@link IntStream}, * etc. Contains methods common to all stream types. Many of these methods - * are implemented by {@link AbstractPipeline}, even though {@code AbstractPipeline} - * does not directly implement {@code BaseStream}. + * are implemented by {@link AbstractPipeline}, even though + * {@code AbstractPipeline} does not directly implement {@code BaseStream}. * * @param <T> Type of stream elements. * @param <S> Type of stream implementing {@code BaseStream}. @@ -41,7 +41,8 @@ /** * Returns an iterator for the elements of this stream. * - * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>. + * <p>This is a <a href="package-summary.html#StreamOps">terminal + * operation</a>. * * @return the element iterator for this stream */ @@ -50,48 +51,56 @@ /** * Returns a spliterator for the elements of this stream. * - * <p>This is a <a href="package-summary.html#StreamOps">terminal operation</a>. + * <p>This is a <a href="package-summary.html#StreamOps">terminal + * operation</a>. * * @return the element spliterator for this stream */ Spliterator<T> spliterator(); /** - * Returns whether this stream, when executed, would execute in parallel (assuming - * no further modification of the stream, such as appending further intermediate - * operations or changing its parallelism). Calling this method after invoking - * an intermediate or terminal stream operation method may yield unpredictable results. + * Returns whether this stream, when executed, would execute in parallel + * (assuming no further modification of the stream, such as appending + * further intermediate operations or changing its parallelism). Calling + * this method after invoking an intermediate or terminal stream operation + * method may yield unpredictable results. * - * @return whether this stream would execute in parallel if executed without further - * modification + * @return whether this stream would execute in parallel if executed without + * further modification */ boolean isParallel(); /** - * Produces an equivalent stream that is sequential. - * If this stream is already sequential, may return itself. + * Produces an equivalent stream that is sequential. May return + * itself, either because the stream was already sequential, or because + * the underlying stream state was modified to be sequential. * - * <p>This is an <a href="package-summary.html#StreamOps">intermediate operation</a>. + * <p>This is an <a href="package-summary.html#StreamOps">intermediate + * operation</a>. * * @return a sequential stream */ S sequential(); /** - * Produces an equivalent stream that is parallel. - * If this stream is already parallel, may return itself. + * Produces an equivalent stream that is parallel. May return + * itself, either because the stream was already parallel, or because + * the underlying stream state was modified to be parallel. * - * <p>This is an <a href="package-summary.html#StreamOps">intermediate operation</a>. + * <p>This is an <a href="package-summary.html#StreamOps">intermediate + * operation</a>. * * @return a parallel stream */ S parallel(); /** - * Produces an equivalent stream that is unordered. If this stream is - * already unordered, may return itself. + * Produces an equivalent stream that is + * <a href="package-summary.html#Ordering">unordered</a>. May return + * itself if the stream was already unordered. * - * <p>This is an <a href="package-summary.html#StreamOps">intermediate operation</a>. + * <p>This is an <a href="package-summary.html#StreamOps">intermediate + * operation</a>. * @return an unordered stream */ S unordered();
--- a/src/share/classes/java/util/stream/Stream.java Fri Apr 05 10:50:31 2013 -0700 +++ b/src/share/classes/java/util/stream/Stream.java Fri Apr 05 14:44:30 2013 -0400 @@ -62,7 +62,18 @@ * stream operations preserve the <a href="package-summary.html#Ordering"> * encounter order</a> of their source, and terminal operations * respect the encounter order of their source, if the source - * has an encounter order. + * has an encounter order. Provided that and parameters to stream operations + * satisfy the <a href="package-summary.html#NonInterference">non-interference + * requirements</a>, and excepting differences arising from the absence of + * a defined encounter order, the result of a stream pipeline should be the + * stable across multiple executions of the same operations on the same source. + * However, the timing and thread in which side-effects occur (for those + * operations which are allowed to produce side-effects, such as + * {@link #forEach(Consumer)}), are explicitly nondeterministic for parallel + * execution of stream pipelines. + * + * <p>Unless otherwise noted, passing a {@code null} argument to any stream + * method may result in a {@link NullPointerException}. * * @apiNote * Streams are not data structures; they do not manage the storage for their @@ -70,9 +81,6 @@ * you can use the {@link #iterator()} or {@link #spliterator()} operations to * perform a controlled traversal. * - * <p>Unless otherwise noted, passing a {@code null} argument to any stream - * method may result in a {@link NullPointerException}. - * * @param <T> Type of elements. * @since 1.8 * @see <a href="package-summary.html">java.util.stream</a> @@ -759,6 +767,7 @@ * * @return An {@code Optional} describing the first element of this stream, * or an empty {@code Optional} if the stream is empty + * @throws NullPointerException if the element selected is null */ Optional<T> findFirst(); @@ -777,6 +786,7 @@ * * @return An {@code Optional} describing some element of this stream, or an * empty {@code Optional} if the stream is empty + * @throws NullPointerException if the element selected is null * @see #findFirst() */ Optional<T> findAny();
--- a/src/share/classes/java/util/stream/package-info.java Fri Apr 05 10:50:31 2013 -0700 +++ b/src/share/classes/java/util/stream/package-info.java Fri Apr 05 14:44:30 2013 -0400 @@ -163,26 +163,42 @@ * * <h3><a name="Ordering">Ordering</a></h3> * - * <p>Streams may or may not have an <em>encounter order</em>. Whether or not there is an - * encounter order depends on the source, the intermediate operations, and the terminal - * operation. Certain stream sources (such as {@code List} or arrays) are intrinsically ordered, - * whereas others (such as {@code HashSet}) are not. Some intermediate operations may impose - * an encounter order on an otherwise unordered stream, such as - * {@link java.util.stream.Stream#sorted()}. Some intermediate operations may remove the - * constraint of ordering, rendering unordered a previously ordered stream. Finally, some - * terminal operations may ignore encounter order, such as {@link java.util.stream.Stream#forEach}, - * and others may have optimized implementations for the case where there is no defined - * encounter order. + * <p>Streams may or may not have an <em>encounter order</em>. Whether or not + * there is an encounter order depends on the source, the intermediate + * operations, and the terminal operation. Certain stream sources (such as + * {@code List} or arrays) are intrinsically ordered, whereas others (such as + * {@code HashSet}) are not. Some intermediate operations may impose an + * encounter order on an otherwise unordered stream, such as + * {@link java.util.stream.Stream#sorted()}, and others may render an ordered + * stream unordered (such as {@link {@link java.util.stream.Stream#unordered()}}). + * Some terminal operations may ignore encounter order, such as + * {@link java.util.stream.Stream#forEach}. * - * <p>If a Stream is ordered, most operations are constrained to operate on the elements in their - * encounter order; if the source of a stream is a {@code List} containing {@code [1, 2, 3]}, - * then the result of executing {@code map(x -> x*2)} must be {@code [2, 4, 6]}. However, if - * the source has no defined encounter order, than any permutation of the values {@code [2, 4, 6]} - * would be a valid result. Many operations can still be efficiently parallelized even under - * ordering constraints, but some (such as duplicate removal) may be more efficient without + * <p>If a Stream is ordered, most operations are constrained to operate on the + * elements in their encounter order; if the source of a stream is a {@code List} + * containing {@code [1, 2, 3]}, then the result of executing {@code map(x -> x*2)} + * must be {@code [2, 4, 6]}. However, if the source has no defined encounter + * order, than any permutation of the values {@code [2, 4, 6]} would be a valid + * result. Many operations can still be efficiently parallelized even under * ordering constraints. * - * TODO Interaction between ordering and concurrency + * <p>For sequential streams, ordering is only relevant to the determinism + * of operations performed repeatedly on the same source. (An {@code ArrayList} + * is constrained to iterate elements in order; a {@code HashSet} is not, and + * repeated iteration might produce a different order.) + * + * <p>For parallel streams, relaxing the ordering constraint can enable + * optimized implementation for some operations. For example, duplicate + * filtration on an ordered stream must completely process the first partition + * before it can return any elements from a subsequent partition, even if those + * elements are available earlier. On the other hand, without the constraint of + * ordering, duplicate filtration can be done more efficiently by using + * a shared {@code ConcurrentHashSet}. There will be cases where the stream + * is structurally ordered (the source is ordered and the intermediate + * operations are order-preserving), but the user does not particularly care + * about the encounter order. In some cases, explicitly de-ordering the stream + * with the {@link java.util.stream.Stream#unordered()} method may result in + * improved parallel performance for some stateful or terminal operations. * * <h2><a name="Non-Interference">Non-interference</h2> * @@ -409,6 +425,43 @@ * .collect(Collectors.toList()); * </pre> * + * <h3><a name="ConcurrentReduction">Reduction, concurrency, and ordering</a></h3> + * + * With some complex reduction operations, such as those that produce a + * {@code Map}, such as: + * <pre> + * Map<Buyer, List<Transaction>> salesByBuyer + * = txns.stream().collect(groupingBy(Transaction::getBuyer)); + * </pre> + * + * it may actually be counterproductive to perform this reduction in parallel, + * because the merging step (merging one {@code Map} into another by key) + * can be expensive for some {@code Map} implementations. + * + * <p>If you are willing to relax the constraint or ordering, there is another + * possibility -- perform a <em>concurrent</em> reduction. This can be done if + * the result container can safely be updated concurrently, such as one that + * collects to a {@code ConcurrentHashMap}. If it is important that the + * elements for a given key appear in the order they appear in the source, then + * we are constrained to implement either a sequential reduction or a + * merge-based parallel reduction. But, if this ordering constraint is + * relaxed, we can also choose to have a shared result container, and let many + * threads update the result container at once, obviating the need for the + * expensive merging step. The + * {@link java.util.stream.Stream#collect(Supplier, BiConsumer, BiConsumer)} + * implementation will choose a concurrent collection if the stream is + * parallel, the {@link java.util.stream.Collector} has the + * {@link java.util.stream.Collector.Characteristics.CONCURRENT} characteristic, + * and either the stream is unordered or the collector has the + * {@link java.util.stream.Collector.Characteristics.UNORDERED} characteristic, + * as in: + * <pre> + * Map<Buyer, List<Transaction>> salesByBuyer + * = txns.stream() + * .unordered() + * .collect(groupingByConcurrent(Transaction::getBuyer)); + * </pre> + * * <a name="Associativity"><h2>Associativity</h2></a> * * An operator or function {@code op} is <em>associative</em> if the following holds: @@ -423,8 +476,8 @@ * the results. * TODO what does associative mean for mutative combining functions? * + * <h2><a name="StreamSources">Stream sources</a></h2> * TODO where does this section go? - * <h2><a name="StreamSources">Stream sources</a></h2> * * XXX - change to section to stream construction gradually introducing more * complex ways to construct @@ -486,3 +539,6 @@ */ package java.util.stream; + +import java.util.function.BiConsumer; +import java.util.function.Supplier; \ No newline at end of file