提交 516d1e97 编写于 作者: H henryjen

8024825: Some fixes are missing from java.util.stream spec update

Reviewed-by: mduigou
上级 eb94c220
...@@ -170,7 +170,6 @@ abstract class ReferencePipeline<P_IN, P_OUT> ...@@ -170,7 +170,6 @@ abstract class ReferencePipeline<P_IN, P_OUT>
} }
@Override @Override
@SuppressWarnings("unchecked")
public void accept(P_OUT u) { public void accept(P_OUT u) {
if (predicate.test(u)) if (predicate.test(u))
downstream.accept(u); downstream.accept(u);
...@@ -264,7 +263,6 @@ abstract class ReferencePipeline<P_IN, P_OUT> ...@@ -264,7 +263,6 @@ abstract class ReferencePipeline<P_IN, P_OUT>
} }
@Override @Override
@SuppressWarnings("unchecked")
public void accept(P_OUT u) { public void accept(P_OUT u) {
try (Stream<? extends R> result = mapper.apply(u)) { try (Stream<? extends R> result = mapper.apply(u)) {
// We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it // We can do better that this too; optimize for depth=0 case and just grab spliterator and forEach it
...@@ -370,7 +368,6 @@ abstract class ReferencePipeline<P_IN, P_OUT> ...@@ -370,7 +368,6 @@ abstract class ReferencePipeline<P_IN, P_OUT>
Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) { Sink<P_OUT> opWrapSink(int flags, Sink<P_OUT> sink) {
return new Sink.ChainedReference<P_OUT, P_OUT>(sink) { return new Sink.ChainedReference<P_OUT, P_OUT>(sink) {
@Override @Override
@SuppressWarnings("unchecked")
public void accept(P_OUT u) { public void accept(P_OUT u) {
action.accept(u); action.accept(u);
downstream.accept(u); downstream.accept(u);
......
...@@ -567,8 +567,8 @@ public interface Stream<T> extends BaseStream<T, Stream<T>> { ...@@ -567,8 +567,8 @@ public interface Stream<T> extends BaseStream<T, Stream<T>> {
/** /**
* Performs a <a href="package-summary.html#Reduction">reduction</a> on the * Performs a <a href="package-summary.html#Reduction">reduction</a> on the
* elements of this stream, using the provided identity, accumulation * elements of this stream, using the provided identity, accumulation and
* function, and combining functions. This is equivalent to: * combining functions. This is equivalent to:
* <pre>{@code * <pre>{@code
* U result = identity; * U result = identity;
* for (T element : this stream) * for (T element : this stream)
...@@ -886,7 +886,7 @@ public interface Stream<T> extends BaseStream<T, Stream<T>> { ...@@ -886,7 +886,7 @@ public interface Stream<T> extends BaseStream<T, Stream<T>> {
* @return the new stream * @return the new stream
*/ */
@SafeVarargs @SafeVarargs
@SuppressWarnings("varargs") @SuppressWarnings("varargs") // Creating a stream from an array is safe
public static<T> Stream<T> of(T... values) { public static<T> Stream<T> of(T... values) {
return Arrays.stream(values); return Arrays.stream(values);
} }
......
...@@ -64,7 +64,7 @@ ...@@ -64,7 +64,7 @@
* operations and terminal (value- or side-effect-producing) operations. * operations and terminal (value- or side-effect-producing) operations.
* Intermediate operations are always lazy.</li> * Intermediate operations are always lazy.</li>
* <li>Possibly unbounded. While collections have a finite size, streams * <li>Possibly unbounded. While collections have a finite size, streams
* need not. Short-circuting operations such as {@code limit(n)} or * need not. Short-circuiting operations such as {@code limit(n)} or
* {@code findFirst()} can allow computations on infinite streams to * {@code findFirst()} can allow computations on infinite streams to
* complete in finite time.</li> * complete in finite time.</li>
* <li>Consumable. The elements of a stream are only visited once during * <li>Consumable. The elements of a stream are only visited once during
...@@ -96,13 +96,13 @@ ...@@ -96,13 +96,13 @@
* *
* <h2><a name="StreamOps">Stream operations and pipelines</a></h2> * <h2><a name="StreamOps">Stream operations and pipelines</a></h2>
* *
* <p>Stream <a href="package-summary.html#StreamOps">operations</a> are * <p>Stream operations are divided into <em>intermediate</em> and
* divided into <em>intermediate</em> and <em>terminal</em> operations, and are * <em>terminal</em> operations, and are combined to form <em>stream
* combined to form <em>stream pipelines</em>. A stream pipeline consists of a * pipelines</em>. A stream pipeline consists of a source (such as a
* source (such as a {@code Collection}, an array, a generator function, or an * {@code Collection}, an array, a generator function, or an I/O channel);
* I/O channel); followed by zero or more intermediate operations such * followed by zero or more intermediate operations such as
* as {@code Stream.filter} or {@code Stream.map}; and a terminal * {@code Stream.filter} or {@code Stream.map}; and a terminal operation such
* operation such as {@code Stream.forEach} or {@code Stream.reduce}. * as {@code Stream.forEach} or {@code Stream.reduce}.
* *
* <p>Intermediate operations return a new stream. They are always * <p>Intermediate operations return a new stream. They are always
* <em>lazy</em>; executing an intermediate operation such as * <em>lazy</em>; executing an intermediate operation such as
...@@ -176,9 +176,10 @@ ...@@ -176,9 +176,10 @@
* do: * do:
* *
* <pre>{@code * <pre>{@code
* int sumOfWeights = widgets.}<b>{@code parallelStream()}</b>{@code .filter(b -> b.getColor() == RED) * int sumOfWeights = widgets.}<code><b>parallelStream()</b></code>{@code
* .mapToInt(b -> b.getWeight()) * .filter(b -> b.getColor() == RED)
* .sum(); * .mapToInt(b -> b.getWeight())
* .sum();
* }</pre> * }</pre>
* *
* <p>The only difference between the serial and parallel versions of this * <p>The only difference between the serial and parallel versions of this
...@@ -485,13 +486,13 @@ ...@@ -485,13 +486,13 @@
* as it collects together the desired results into a result container such * as it collects together the desired results into a result container such
* as a {@code Collection}. * as a {@code Collection}.
* A {@code collect} operation requires three functions: * A {@code collect} operation requires three functions:
* a factory function to construct new instances of the result container, an * a supplier function to construct new instances of the result container, an
* accumulator function to incorporate an input element into a result * accumulator function to incorporate an input element into a result
* container, and a combining function to merge the contents of one result * container, and a combining function to merge the contents of one result
* container into another. The form of this is very similar to the general * container into another. The form of this is very similar to the general
* form of ordinary reduction: * form of ordinary reduction:
* <pre>{@code * <pre>{@code
* <R> R collect(Supplier<R> resultFactory, * <R> R collect(Supplier<R> supplier,
* BiConsumer<R, ? super T> accumulator, * BiConsumer<R, ? super T> accumulator,
* BiConsumer<R, R> combiner); * BiConsumer<R, R> combiner);
* }</pre> * }</pre>
...@@ -525,10 +526,10 @@ ...@@ -525,10 +526,10 @@
* {@code ArrayList}, and the combiner simply uses {@link java.util.ArrayList#addAll addAll} * {@code ArrayList}, and the combiner simply uses {@link java.util.ArrayList#addAll addAll}
* to copy the strings from one container into the other. * to copy the strings from one container into the other.
* *
* <p> The three aspects of {@code collect} -- supplier, accumulator, and combiner -- * <p>The three aspects of {@code collect} -- supplier, accumulator, and
* are tightly coupled. We can use the abstraction of * combiner -- are tightly coupled. We can use the abstraction of a
* of a {@link java.util.stream.Collector} to capture all three aspects. * {@link java.util.stream.Collector} to capture all three aspects. The
* The above example for collecting strings into a {@code List} can be rewritten * above example for collecting strings into a {@code List} can be rewritten
* using a standard {@code Collector} as: * using a standard {@code Collector} as:
* <pre>{@code * <pre>{@code
* List<String> strings = stream.map(Object::toString) * List<String> strings = stream.map(Object::toString)
...@@ -545,7 +546,7 @@ ...@@ -545,7 +546,7 @@
* <pre>{@code * <pre>{@code
* Collector<Employee, ?, Integer> summingSalaries * Collector<Employee, ?, Integer> summingSalaries
* = Collectors.summingInt(Employee::getSalary); * = Collectors.summingInt(Employee::getSalary);
* } </pre> * }</pre>
* *
* (The {@code ?} for the second type parameter merely indicates that we don't * (The {@code ?} for the second type parameter merely indicates that we don't
* care about the intermediate representation used by this collector.) * care about the intermediate representation used by this collector.)
...@@ -557,14 +558,15 @@ ...@@ -557,14 +558,15 @@
* Map<Department, Integer> salariesByDept * Map<Department, Integer> salariesByDept
* = employees.stream().collect(Collectors.groupingBy(Employee::getDepartment, * = employees.stream().collect(Collectors.groupingBy(Employee::getDepartment,
* summingSalaries)); * summingSalaries));
* } </pre> * }</pre>
* *
* <p>As with the regular reduction operation, {@code collect()} operations can * <p>As with the regular reduction operation, {@code collect()} operations can
* only be parallelized if appropriate conditions are met. For any partially accumulated result, * only be parallelized if appropriate conditions are met. For any partially
* combining it with an empty result container must produce an equivalent * accumulated result, combining it with an empty result container must
* result. That is, for a partially accumulated result {@code p} that is the * produce an equivalent result. That is, for a partially accumulated result
* result of any series of accumulator and combiner invocations, {@code p} must * {@code p} that is the result of any series of accumulator and combiner
* be equivalent to {@code combiner.apply(p, supplier.get())}. * invocations, {@code p} must be equivalent to
* {@code combiner.apply(p, supplier.get())}.
* *
* <p>Further, however the computation is split, it must produce an equivalent * <p>Further, however the computation is split, it must produce an equivalent
* result. For any input elements {@code t1} and {@code t2}, the results * result. For any input elements {@code t1} and {@code t2}, the results
...@@ -580,7 +582,7 @@ ...@@ -580,7 +582,7 @@
* A a3 = supplier.get(); * A a3 = supplier.get();
* accumulator.accept(a3, t2); * accumulator.accept(a3, t2);
* R r2 = finisher.apply(combiner.apply(a2, a3)); // result with splitting * R r2 = finisher.apply(combiner.apply(a2, a3)); // result with splitting
* } </pre> * }</pre>
* *
* <p>Here, equivalence generally means according to {@link java.lang.Object#equals(Object)}. * <p>Here, equivalence generally means according to {@link java.lang.Object#equals(Object)}.
* but in some cases equivalence may be relaxed to account for differences in * but in some cases equivalence may be relaxed to account for differences in
...@@ -596,8 +598,8 @@ ...@@ -596,8 +598,8 @@
* .collect(Collectors.groupingBy(Transaction::getBuyer)); * .collect(Collectors.groupingBy(Transaction::getBuyer));
* }</pre> * }</pre>
* it may actually be counterproductive to perform the operation in parallel. * it may actually be counterproductive to perform the operation in parallel.
* This is because the combining step (merging one {@code Map} into another by key) * This is because the combining step (merging one {@code Map} into another by
* can be expensive for some {@code Map} implementations. * key) can be expensive for some {@code Map} implementations.
* *
* <p>Suppose, however, that the result container used in this reduction * <p>Suppose, however, that the result container used in this reduction
* was a concurrently modifiable collection -- such as a * was a concurrently modifiable collection -- such as a
...@@ -605,8 +607,8 @@ ...@@ -605,8 +607,8 @@
* invocations of the accumulator could actually deposit their results * invocations of the accumulator could actually deposit their results
* concurrently into the same shared result container, eliminating the need for * concurrently into the same shared result container, eliminating the need for
* the combiner to merge distinct result containers. This potentially provides * the combiner to merge distinct result containers. This potentially provides
* a boost to the parallel execution performance. We call this a <em>concurrent</em> * a boost to the parallel execution performance. We call this a
* reduction. * <em>concurrent</em> reduction.
* *
* <p>A {@link java.util.stream.Collector} that supports concurrent reduction is * <p>A {@link java.util.stream.Collector} that supports concurrent reduction is
* marked with the {@link java.util.stream.Collector.Characteristics#CONCURRENT} * marked with the {@link java.util.stream.Collector.Characteristics#CONCURRENT}
...@@ -635,11 +637,11 @@ ...@@ -635,11 +637,11 @@
* (where {@link java.util.stream.Collectors#groupingByConcurrent} is the * (where {@link java.util.stream.Collectors#groupingByConcurrent} is the
* concurrent equivalent of {@code groupingBy}). * concurrent equivalent of {@code groupingBy}).
* *
* <p>Note that if it is important that the elements for a given key appear in the * <p>Note that if it is important that the elements for a given key appear in
* order they appear in the source, then we cannot use a concurrent reduction, * the order they appear in the source, then we cannot use a concurrent
* as ordering is one of the casualties of concurrent insertion. We would then * reduction, as ordering is one of the casualties of concurrent insertion.
* be constrained to implement either a sequential reduction or a merge-based * We would then be constrained to implement either a sequential reduction or
* parallel reduction. * a merge-based parallel reduction.
* *
* <h3><a name="Associativity">Associativity</a></h3> * <h3><a name="Associativity">Associativity</a></h3>
* *
...@@ -656,8 +658,8 @@ ...@@ -656,8 +658,8 @@
* So we can evaluate {@code (a op b)} in parallel with {@code (c op d)}, and * So we can evaluate {@code (a op b)} in parallel with {@code (c op d)}, and
* then invoke {@code op} on the results. * then invoke {@code op} on the results.
* *
* <p>Examples of associative operations include numeric addition, min, and max, * <p>Examples of associative operations include numeric addition, min, and
* and string concatenation. * max, and string concatenation.
* *
* <h2><a name="StreamSources">Low-level stream construction</a></h2> * <h2><a name="StreamSources">Low-level stream construction</a></h2>
* *
...@@ -665,48 +667,54 @@ ...@@ -665,48 +667,54 @@
* {@link java.util.Collection#stream()} or {@link java.util.Arrays#stream(Object[])} * {@link java.util.Collection#stream()} or {@link java.util.Arrays#stream(Object[])}
* to obtain a stream. How are those stream-bearing methods implemented? * to obtain a stream. How are those stream-bearing methods implemented?
* *
* <p>The class {@link java.util.stream.StreamSupport} has a number of low-level * <p>The class {@link java.util.stream.StreamSupport} has a number of
* methods for creating a stream, all using some form of a {@link java.util.Spliterator}. * low-level methods for creating a stream, all using some form of a
* A spliterator is the parallel analogue of an {@link java.util.Iterator}; it * {@link java.util.Spliterator}. A spliterator is the parallel analogue of an
* describes a (possibly infinite) collection of elements, with support for * {@link java.util.Iterator}; it describes a (possibly infinite) collection of
* sequentially advancing, bulk traversal, and splitting off some portion of the * elements, with support for sequentially advancing, bulk traversal, and
* input into another spliterator which can be processed in parallel. At the * splitting off some portion of the input into another spliterator which can
* lowest level, all streams are driven by a spliterator. * be processed in parallel. At the lowest level, all streams are driven by a
* * spliterator.
* <p>There are a number of implementation choices in implementing a spliterator, *
* nearly all of which are tradeoffs between simplicity of implementation and * <p>There are a number of implementation choices in implementing a
* runtime performance of streams using that spliterator. The simplest, but * spliterator, nearly all of which are tradeoffs between simplicity of
* least performant, way to create a spliterator is to create one from an iterator * implementation and runtime performance of streams using that spliterator.
* using {@link java.util.Spliterators#spliteratorUnknownSize(java.util.Iterator, int)}. * The simplest, but least performant, way to create a spliterator is to
* create one from an iterator using
* {@link java.util.Spliterators#spliteratorUnknownSize(java.util.Iterator, int)}.
* While such a spliterator will work, it will likely offer poor parallel * While such a spliterator will work, it will likely offer poor parallel
* performance, since we have lost sizing information (how big is the underlying * performance, since we have lost sizing information (how big is the
* data set), as well as being constrained to a simplistic splitting algorithm. * underlying data set), as well as being constrained to a simplistic
* splitting algorithm.
* *
* <p>A higher-quality spliterator will provide balanced and known-size splits, * <p>A higher-quality spliterator will provide balanced and known-size
* accurate sizing information, and a number of other * splits, accurate sizing information, and a number of other
* {@link java.util.Spliterator#characteristics() characteristics} of the * {@link java.util.Spliterator#characteristics() characteristics} of the
* spliterator or data that can be used by implementations to optimize * spliterator or data that can be used by implementations to optimize
* execution. * execution.
* *
* <p>Spliterators for mutable data sources have an additional challenge; timing * <p>Spliterators for mutable data sources have an additional challenge;
* of binding to the data, since the data could change between the time the * timing of binding to the data, since the data could change between the time
* spliterator is created and the time the stream pipeline is executed. Ideally, * the spliterator is created and the time the stream pipeline is executed.
* a spliterator for a stream would report a characteristic of {@code IMMUTABLE} * Ideally, a spliterator for a stream would report a characteristic of
* or {@code CONCURRENT}; if not it should be <a href="../Spliterator.html#binding"><em>late-binding</em></a>.
* If a source cannot directly supply a recommended spliterator, it may * {@code IMMUTABLE} or {@code CONCURRENT}; if not it should be
* indirectly supply a spliterator using a {@code Supplier}, and construct a * <a href="../Spliterator.html#binding"><em>late-binding</em></a>. If a source
* stream via the {@code Supplier}-accepting versions of * cannot directly supply a recommended spliterator, it may indirectly supply
* a spliterator using a {@code Supplier}, and construct a stream via the
* {@code Supplier}-accepting versions of
* {@link java.util.stream.StreamSupport#stream(Supplier, int, boolean) stream()}. * {@link java.util.stream.StreamSupport#stream(Supplier, int, boolean) stream()}.
* The spliterator is obtained from the supplier only after the terminal * The spliterator is obtained from the supplier only after the terminal
* operation of the stream pipeline commences. * operation of the stream pipeline commences.
* *
* <p>These requirements significantly reduce the scope of potential interference * <p>These requirements significantly reduce the scope of potential
* between mutations of the stream source and execution of stream pipelines. * interference between mutations of the stream source and execution of stream
* Streams based on spliterators with the desired characteristics, or those using * pipelines. Streams based on spliterators with the desired characteristics,
* the Supplier-based factory forms, are immune to modifications of the data * or those using the Supplier-based factory forms, are immune to
* source prior to commencement of the terminal operation (provided the behavioral * modifications of the data source prior to commencement of the terminal
* parameters to the stream operations meet the required criteria for non-interference * operation (provided the behavioral parameters to the stream operations meet
* and statelessness). See <a href="package-summary.html#Non-Interference">Non-Interference</a> * the required criteria for non-interference and statelessness). See
* <a href="package-summary.html#Non-Interference">Non-Interference</a>
* for more details. * for more details.
* *
* @since 1.8 * @since 1.8
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册