├── .github └── workflows │ └── maven.yml ├── .gitignore ├── LICENSE ├── README.MD ├── pom.xml └── src ├── main └── java │ └── com │ └── github │ └── ferstl │ └── streams │ ├── AbstractParallelStreamSupport.java │ ├── ParallelDoubleStreamSupport.java │ ├── ParallelIntStreamSupport.java │ ├── ParallelLongStreamSupport.java │ └── ParallelStreamSupport.java └── test └── java └── com └── github └── ferstl └── streams ├── AbstractParallelStreamSupportTest.java ├── ParallelDoubleStreamSupportTest.java ├── ParallelIntStreamSupportTest.java ├── ParallelLongStreamSupportTest.java └── ParallelStreamSupportTest.java /.github/workflows/maven.yml: -------------------------------------------------------------------------------- 1 | name: Java CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Set up JDK 15 16 | uses: actions/setup-java@v2 17 | with: 18 | java-version: 15 19 | distribution: 'zulu' 20 | cache: maven 21 | - name: Maven Build 22 | run: mvn clean install -Pgenerate-javadoc 23 | - name: Coveralls Report 24 | run: mvn org.jacoco:jacoco-maven-plugin:prepare-agent test org.jacoco:jacoco-maven-plugin:report org.eluder.coveralls:coveralls-maven-plugin:report -DrepoToken=${{ secrets.COVERALLS_TOKEN }} 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | .classpath 3 | .settings/org.eclipse.core.resources.prefs 4 | /target 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Stefan Ferstl 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # Parallel Stream Support 2 | *- Parallel streams in Java with a custom ForkJoinPool* 3 | 4 | [![Build Status](https://github.com/ferstl/parallel-stream-support/actions/workflows/maven.yml/badge.svg)](https://github.com/ferstl/parallel-stream-support/actions/workflows/maven.yml) [![Coverage Status](https://coveralls.io/repos/github/ferstl/parallel-stream-support/badge.svg?branch=master)](https://coveralls.io/github/ferstl/parallel-stream-support?branch=master) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.ferstl/parallel-stream-support/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.ferstl/parallel-stream-support) [![Javadocs](http://javadoc.io/badge/com.github.ferstl/parallel-stream-support.svg?color=blue)](http://javadoc.io/doc/com.github.ferstl/parallel-stream-support) [![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)](https://opensource.org/licenses/MIT) 5 | 6 | Parallel streams are by default processed in the [common pool](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/concurrent/ForkJoinPool.html#commonPool()--). This is fine for many cases but sometimes it is not useful since there is no control over what else is running in the common pool. For example, an external library might use the common pool for IO-intensive tasks and therefore prevent the performance critical parallel streams of your application from executing. The stream API does not offer a mechanism to process parallel streams in a user-defined thread pool. 7 | 8 | This library works around this gap and offers parallel streams in dedicated [ForkJoinPools](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/concurrent/ForkJoinPool.html). Like the standard stream API this library offers streams for Java objects and for `int`, `long` and `double` primitive types. 9 | 10 | :warning: Having parallel streams outside of the common pool is not an officially supported feature and might stop working or behave differently in later Java releases! Furthermore the splitting policy of Parallel Streams depends strongly on the configured parallelism of the common pool. See this [StackOverflow Answer](http://stackoverflow.com/a/29272776/1497059) from Stuart Marks for further details: 11 | 12 | > In the [java.util.stream.AbstractTask](http://hg.openjdk.java.net/jdk/jdk15/file/jdk-15-ga/src/java.base/share/classes/java/util/stream/AbstractTask.java) class, the LEAF_TARGET field determines the amount of splitting that is done, which in turn determines the amount of parallelism that can be achieved. The value of this field is based on `ForkJoinPool.getCommonPoolParallelism()` which of course uses the parallelism of the common pool, not whatever pool happens to be running the tasks. 13 | 14 | # How to Use 15 | ## Version Compatibility 16 | Each major version of this library belongs to one or more major versions of the JDK: 17 | 18 | | Library Version | JDK Version(s) | Comment | 19 | | --- | --- | --- | 20 | | 1.x.x | JDK 8 | Covers all methods of `Stream` and its primitive variants. | 21 | | 2.x.x | JDKs 9-15 | Adds support for `takeWhile()` and `dropWhile()` | 22 | 23 | ## Dependencies 24 | 25 | The *Parallel Stream Support* library is available on [Maven Central](http://central.maven.org/maven2/com/github/ferstl/parallel-stream-support/). So no further repository configuration is required. 26 | 27 | 28 | 29 | com.github.ferstl 30 | parallel-stream-support 31 | 2.0.0 32 | 33 | 34 | 35 | ## Creating Parallel Streams 36 | To create a parallel stream you need to instantiate a [ForkJoinPool](https://docs.oracle.com/en/java/javase/ 37 | /docs/api/java.base/java/util/concurrent/ForkJoinPool.html) and call one of the static factory methods of [ParallelStreamSupport](http://static.javadoc.io/com.github.ferstl/parallel-stream-support/2.0.0/com/github/ferstl/streams/ParallelStreamSupport.html), [ParallelIntStreamSupport](http://static.javadoc.io/com.github.ferstl/parallel-stream-support/2.0.0/com/github/ferstl/streams/ParallelIntStreamSupport.html), [ParallelLongStreamSupport](http://static.javadoc.io/com.github.ferstl/parallel-stream-support/2.0.0/com/github/ferstl/streams/ParallelLongStreamSupport.html) or [ParallelDoubleStreamSupport](http://static.javadoc.io/com.github.ferstl/parallel-stream-support/2.0.0/com/github/ferstl/streams/ParallelDoubleStreamSupport.html). The factory methods are based on: 38 | 39 | - The static factory methods of the [Stream](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/stream/Stream.html) interface or its primitive variants 40 | - The static factory methods of [StreamSupport](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/stream/StreamSupport.html) 41 | - [Collection.parallelStream()](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Collection.html#parallelStream--) 42 | - [Arrays.stream()](hhttps://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/Arrays.html#stream-T:A-) 43 | 44 | Take a look at the [Javadoc](https://javadoc.io/doc/com.github.ferstl/parallel-stream-support/) for a complete overview of the factory methods. 45 | 46 | **Example 1: Calculate the average weight of Elements** 47 | 48 | public double getAverageWeight(Collection elements) { 49 | ForkJoinPool pool = new ForkJoinPool(NR_OF_THREADS); 50 | 51 | double averageWeight = ParallelStreamSupport.parallelStream(elements, pool) 52 | .filter(Element::isAvailable) 53 | .mapToDouble(Element::getWeight) 54 | .average() 55 | .orElse(0.0); 56 | 57 | return averageWeight; 58 | } 59 | 60 | **Example 2: Find a particular number in a random Array** 61 | 62 | public void find42(int[] randomArray) { 63 | ForkJoinPool pool = new ForkJoinPool(); 64 | 65 | ParallelIntStreamSupport.parallelStream(randomArray, pool) 66 | .filter(i -> i == 42) 67 | .findAny() 68 | .orElseThrow(IllegalStateException::new); 69 | } 70 | 71 | # FAQ 72 | Q: How does it work? 73 | 74 | A: The mechanism is pretty simple. A terminal operation on a parallel stream will recognize if it is executed within a ForkJoinPool. If it is not, the execution will be handed over to the common pool. If the operation was already started in a ForkJoinPool it will use that pool to complete the operation. This library utilizes this behavior and makes sure that terminal operations are started as task in the user-defined ForkJoinPool. 75 | 76 | ----- 77 | 78 | Q: Does this library also support sequential streams? 79 | 80 | A: Yes. Just call `sequential()` on the stream and it will be processed within the calling thread. When created, all streams of this library are configured to be parallel. 81 | 82 | ----- 83 | 84 | Q: Why is there no public constructor which takes a regular Java stream and a ForkJoinPool? 85 | 86 | A: It is a strong principle of this library to hide the details of its implementation. So the only place you have to deal with a concrete class of this library is when a new parallel stream is created. Afterwards you will only see the standard interfaces Stream, IntStream, LongStream and DoubleStream. Furthermore, each stream variant offers similar factory methods as in [StreamSupport](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/stream/StreamSupport.html), which allows you to create a parallel stream from any other stream by just calling [Stream.spliterator()](https://docs.oracle.com/en/java/javase/15/docs/api/java.base/java/util/stream/BaseStream.html#spliterator--). 87 | Should you still think an essential factory method is missing, please report an [issue](https://github.com/ferstl/parallel-stream-support/issues) on this project. 88 | 89 | # How to Build 90 | 91 | # Normal build with Javadoc and tests 92 | mvn clean install -Pgenerate-javadoc 93 | 94 | # Release 95 | mvn release:preapare release:perform 96 | 97 | # Coverage and publish to Coveralls 98 | # (reopToken not required on Travis) 99 | mvn clean jacoco:prepare-agent test jacoco:report coveralls:report -DrepoToken= 100 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4.0.0 3 | 4 | com.github.ferstl 5 | parallel-stream-support 6 | 2.0.1-SNAPSHOT 7 | 8 | Parallel Stream Support 9 | https://github.com/ferstl/parallel-stream-support 10 | 11 | Parallel streams in Java with a custom ForkJoinPool. 12 | 13 | 14 | 15 | 16 | MIT 17 | http://opensource.org/licenses/MIT 18 | repo 19 | 20 | 21 | 22 | 23 | Github 24 | https://github.com/ferstl/parallel-stream-support/issues 25 | 26 | 27 | 28 | Travis CI 29 | https://travis-ci.org/ferstl/parallel-stream-support 30 | 31 | 32 | 33 | 34 | ferstl 35 | Stefan Ferstl 36 | st.ferstl@gmail.com 37 | https://github.com/ferstl 38 | +1 39 | 40 | 41 | 42 | 43 | scm:git:https://github.com/ferstl/parallel-stream-support.git 44 | scm:git:git@github.com:ferstl/parallel-stream-support.git 45 | ${project.url} 46 | HEAD 47 | 48 | 49 | 50 | 51 | ${distribution.release.id} 52 | ${distribution.release.url} 53 | 54 | 55 | ${distribution.snapshot.id} 56 | ${distribution.snapshot.url} 57 | 58 | 59 | 60 | 61 | 62 | 4.1 63 | 3.1.0 64 | 3.8.1 65 | 2.8.2 66 | 3.0.1 67 | 2.5.2 68 | 3.2.0 69 | 3.3.0 70 | 2.5.3 71 | 3.2.0 72 | 3.2.1 73 | 2.22.2 74 | 4.3.0 75 | 0.8.7 76 | 77 | 78 | UTF-8 79 | UTF-8 80 | ${java.home}/lib/src.zip 81 | 3.3.9 82 | 83 | 84 | 85 | 86 | 87 | org.junit 88 | junit-bom 89 | 5.7.2 90 | pom 91 | import 92 | 93 | 94 | 95 | 96 | 97 | 98 | org.junit.jupiter 99 | junit-jupiter 100 | test 101 | 102 | 103 | 104 | org.hamcrest 105 | java-hamcrest 106 | 2.0.0.0 107 | test 108 | 109 | 110 | 111 | org.mockito 112 | mockito-core 113 | 3.12.4 114 | test 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | com.mycila 123 | license-maven-plugin 124 | ${license-maven-plugin.version} 125 | 126 |
${basedir}/LICENSE
127 | true 128 | 129 | SLASHSTAR_STYLE 130 | 131 | 132 | src/main/** 133 | src/test/java/** 134 | 135 |
136 |
137 | 138 | 139 | org.apache.maven.plugins 140 | maven-clean-plugin 141 | ${maven-clean-plugin.version} 142 | 143 | 144 | 145 | org.apache.maven.plugins 146 | maven-compiler-plugin 147 | ${maven-compiler-plugin.version} 148 | 149 | 9 150 | 151 | 152 | 153 | 154 | org.apache.maven.plugins 155 | maven-deploy-plugin 156 | ${maven-deploy-plugin.version} 157 | 158 | 159 | 160 | org.apache.maven.plugins 161 | maven-gpg-plugin 162 | ${maven-gpg-plugin.version} 163 | 164 | 165 | 166 | org.apache.maven.plugins 167 | maven-install-plugin 168 | ${maven-install-plugin.version} 169 | 170 | 171 | 172 | org.apache.maven.plugins 173 | maven-jar-plugin 174 | ${maven-jar-plugin.version} 175 | 176 | 177 | 178 | org.apache.maven.plugins 179 | maven-javadoc-plugin 180 | ${maven-javadoc-plugin.version} 181 | 182 | 183 | 184 | org.apache.maven.plugins 185 | maven-release-plugin 186 | ${maven-release-plugin.version} 187 | 188 | forked-path 189 | false 190 | -Pdeploy-to-sonatype-oss,generate-javadoc 191 | 192 | 193 | 194 | 195 | org.apache.maven.plugins 196 | maven-resources-plugin 197 | ${maven-resources-plugin.version} 198 | 199 | 200 | 201 | org.apache.maven.plugins 202 | maven-source-plugin 203 | ${maven-source-plugin.version} 204 | 205 | 206 | 207 | org.apache.maven.plugins 208 | maven-surefire-plugin 209 | ${maven-surefire-plugin.version} 210 | 211 | 212 | 213 | org.eluder.coveralls 214 | coveralls-maven-plugin 215 | ${coveralls-maven-plugin.version} 216 | 217 | 218 | org.glassfish.jaxb 219 | jaxb-runtime 220 | 2.3.5 221 | 222 | 223 | 224 | 225 | 226 | org.jacoco 227 | jacoco-maven-plugin 228 | ${jacoco-maven-plugin.version} 229 | 230 |
231 |
232 | 233 | 234 | 235 | org.apache.maven.plugins 236 | maven-source-plugin 237 | 238 | 239 | attach-sources 240 | 241 | jar-no-fork 242 | 243 | 244 | 245 | 246 | 247 |
248 | 249 | 250 | 251 | generate-javadoc 252 | 253 | false 254 | 255 | 256 | 257 | 258 | com.oracle 259 | java 260 | 1.8 261 | system 262 | sources 263 | zip 264 | ${src.zip.location} 265 | 266 | 267 | 268 | 269 | 270 | 271 | org.apache.maven.plugins 272 | maven-dependency-plugin 273 | 274 | 275 | unpack-java-src 276 | prepare-package 277 | 278 | unpack-dependencies 279 | 280 | 281 | system 282 | **/java/util/**/*.java 283 | 284 | 285 | 286 | 287 | 288 | org.apache.maven.plugins 289 | maven-javadoc-plugin 290 | 291 | com.github.ferstl 292 | ${project.build.sourceDirectory};${project.build.directory}/dependency 293 | 294 | https://docs.oracle.com/en/java/javase/11/docs/api/ 295 | 296 | 297 | 298 | apiNote 299 | a 300 | API Note: 301 | 302 | 303 | implSpec 304 | a 305 | Implementation Requirements: 306 | 307 | 308 | implNote 309 | a 310 | Implementation Note: 311 | 312 | 313 | 314 | 315 | 316 | attach-javadocs 317 | package 318 | 319 | jar 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | deploy-to-sonatype-oss 330 | 331 | 332 | 333 | org.apache.maven.plugins 334 | maven-gpg-plugin 335 | 336 | 337 | sign-artifacts 338 | verify 339 | 340 | sign 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 |
350 | -------------------------------------------------------------------------------- /src/main/java/com/github/ferstl/streams/AbstractParallelStreamSupport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Stefan Ferstl 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.github.ferstl.streams; 23 | 24 | import java.util.Iterator; 25 | import java.util.Spliterator; 26 | import java.util.concurrent.Callable; 27 | import java.util.concurrent.ForkJoinPool; 28 | import java.util.concurrent.ForkJoinTask; 29 | import java.util.stream.BaseStream; 30 | import static java.util.Objects.requireNonNull; 31 | import static java.util.concurrent.ForkJoinTask.adapt; 32 | 33 | /** 34 | * Abstract base class for all parallel streams in this package. It implements all Methods of {@link BaseStream} and 35 | * holds the {@link ForkJoinPool} and the stream to which subsequent stream operations are delegated. The two methods 36 | * {@link #execute(Callable)} and {@link #execute(Runnable)} are used to execute terminal operations. In case this 37 | * stream's {@link #isParallel()} method returns {@code true}, a terminal operation will be executed as 38 | * {@link ForkJoinTask} in the {@link #workerPool}. Otherwise the terminal operation will be executed in the calling 39 | * thread. 40 | * 41 | * @param The type of the stream elements. 42 | * @param Type of stream. 43 | */ 44 | abstract class AbstractParallelStreamSupport> implements BaseStream { 45 | 46 | S delegate; 47 | final ForkJoinPool workerPool; 48 | 49 | AbstractParallelStreamSupport(S delegate, ForkJoinPool workerPool) { 50 | requireNonNull(delegate, "Stream must not be null"); 51 | requireNonNull(workerPool, "Worker pool must not be null"); 52 | 53 | this.delegate = delegate; 54 | this.workerPool = workerPool; 55 | } 56 | 57 | @Override 58 | public boolean isParallel() { 59 | return this.delegate.isParallel(); 60 | } 61 | 62 | @Override 63 | public Iterator iterator() { 64 | return this.delegate.iterator(); 65 | } 66 | 67 | @Override 68 | public Spliterator spliterator() { 69 | return this.delegate.spliterator(); 70 | } 71 | 72 | @Override 73 | @SuppressWarnings("unchecked") 74 | public S sequential() { 75 | this.delegate = this.delegate.sequential(); 76 | return (S) this; 77 | } 78 | 79 | @Override 80 | @SuppressWarnings("unchecked") 81 | public S parallel() { 82 | this.delegate = this.delegate.parallel(); 83 | return (S) this; 84 | } 85 | 86 | @Override 87 | @SuppressWarnings("unchecked") 88 | public S unordered() { 89 | this.delegate = this.delegate.unordered(); 90 | return (S) this; 91 | } 92 | 93 | @Override 94 | @SuppressWarnings("unchecked") 95 | public S onClose(Runnable closeHandler) { 96 | this.delegate = this.delegate.onClose(closeHandler); 97 | return (S) this; 98 | } 99 | 100 | @Override 101 | public void close() { 102 | this.delegate.close(); 103 | } 104 | 105 | protected void execute(Runnable terminalOperation) { 106 | if (isParallel()) { 107 | ForkJoinTask task = adapt(terminalOperation); 108 | this.workerPool.invoke(task); 109 | } else { 110 | terminalOperation.run(); 111 | } 112 | } 113 | 114 | protected R execute(Callable terminalOperation) { 115 | if (isParallel()) { 116 | ForkJoinTask task = adapt(terminalOperation); 117 | return this.workerPool.invoke(task); 118 | } 119 | 120 | try { 121 | return terminalOperation.call(); 122 | } catch (RuntimeException | Error e) { 123 | throw e; 124 | } catch (Exception e) { 125 | throw new RuntimeException(e); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /src/main/java/com/github/ferstl/streams/ParallelDoubleStreamSupport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Stefan Ferstl 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.github.ferstl.streams; 23 | 24 | import java.util.Arrays; 25 | import java.util.DoubleSummaryStatistics; 26 | import java.util.OptionalDouble; 27 | import java.util.PrimitiveIterator.OfDouble; 28 | import java.util.Spliterator; 29 | import java.util.concurrent.ForkJoinPool; 30 | import java.util.concurrent.ForkJoinTask; 31 | import java.util.function.BiConsumer; 32 | import java.util.function.DoubleBinaryOperator; 33 | import java.util.function.DoubleConsumer; 34 | import java.util.function.DoubleFunction; 35 | import java.util.function.DoublePredicate; 36 | import java.util.function.DoubleSupplier; 37 | import java.util.function.DoubleToIntFunction; 38 | import java.util.function.DoubleToLongFunction; 39 | import java.util.function.DoubleUnaryOperator; 40 | import java.util.function.ObjDoubleConsumer; 41 | import java.util.function.Supplier; 42 | import java.util.stream.DoubleStream; 43 | import java.util.stream.IntStream; 44 | import java.util.stream.LongStream; 45 | import java.util.stream.Stream; 46 | import java.util.stream.StreamSupport; 47 | import static java.util.Arrays.stream; 48 | import static java.util.Objects.requireNonNull; 49 | import static java.util.stream.StreamSupport.doubleStream; 50 | 51 | /** 52 | *

53 | * An implementation of {@link DoubleStream} which uses a custom {@link ForkJoinPool} for parallel aggregate 54 | * operations. This is the {@code double} primitive specialization of {@link ParallelStreamSupport}. 55 | *

56 | * The following example illustrates an aggregate operation using {@link ParallelStreamSupport} and 57 | * {@link ParallelDoubleStreamSupport} with a custom {@link ForkJoinPool}, computing the sum of the weights of the red 58 | * widgets: 59 | *

 60 |  * ForkJoinPool pool = new ForkJoinPool();
 61 |  * double sum = ParallelStreamSupport.parallelStream(widgets, pool)
 62 |  *     .filter(w -> w.getColor() == RED)
 63 |  *     .mapToDouble(w -> w.getWeight())
 64 |  *     .sum();
 65 |  * 
66 | *

67 | * In case this stream is configured for parallel execution, i.e. {@link #isParallel()} returns {@code true}, a 68 | * terminal 69 | * operation will be executed as {@link ForkJoinTask} in the custom {@link ForkJoinPool}. Otherwise it will be 70 | * executed in the calling thread. 71 | *

72 | * This implementation offers various factory methods which are based on: 73 | *
    74 | *
  • The static factory methods of {@link DoubleStream}, which are meaningful for parallel streams
  • 75 | *
  • {@link Arrays#stream(double[])}
  • 76 | *
  • {@link StreamSupport#doubleStream(Spliterator.OfDouble, boolean)}
  • 77 | *
  • {@link StreamSupport#doubleStream(Supplier, int, boolean)}
  • 78 | *
79 | * 80 | * @apiNote

81 | * Internally, this stream wraps a {@code double} stream which is initially created in one of the static factory 82 | * methods. Whenever a non-terminal operation is called the underlying stream will be replaced with the result of 83 | * calling the same method on that stream. The return value of these operations is always this stream or, in case of 84 | * operations that return a different type of stream, one of {@link ParallelStreamSupport}, 85 | * {@link ParallelIntStreamSupport} or {@link ParallelLongStreamSupport}. 86 | *

87 | *

88 | * Although each factory method returns a parallel stream, calling {@link #sequential()} is still possible and leads to 89 | * sequential execution of a terminal operation within the calling thread. 90 | *

91 | * @implNote

92 | * See the class documentation for {@link Stream} and the package documentation for 93 | * java.util.stream for 94 | * additional specification. 95 | *

96 | */ 97 | public class ParallelDoubleStreamSupport extends AbstractParallelStreamSupport implements DoubleStream { 98 | 99 | /** 100 | * Constructor for internal use within this package only. 101 | * 102 | * @param delegate Stream to delegate each operation. 103 | * @param workerPool Worker pool for executing terminal operations in parallel. Must not be {@code null}. 104 | */ 105 | ParallelDoubleStreamSupport(DoubleStream delegate, ForkJoinPool workerPool) { 106 | super(delegate, workerPool); 107 | } 108 | 109 | /** 110 | * Creates a parallel {@code double} stream from the given Array. This operation is similar to 111 | * calling {@code Arrays.stream(array).parallel()} with the difference that a parallel 112 | * terminal 113 | * operation will be executed in the given {@link ForkJoinPool}. 114 | * 115 | * @param array Array to create the parallel stream from. Must not be {@code null}. 116 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 117 | * @return A parallel {@code double} stream that executes a terminal operation in the given {@link ForkJoinPool}. 118 | * @see Arrays#stream(int[]) 119 | */ 120 | public static DoubleStream parallelStream(double[] array, ForkJoinPool workerPool) { 121 | requireNonNull(array, "Array must not be null"); 122 | 123 | return new ParallelDoubleStreamSupport(stream(array).parallel(), workerPool); 124 | } 125 | 126 | /** 127 | * Creates a parallel {@code double} stream from the given Spliterator. This operation is similar to 128 | * calling {@code StreamSupport.doubleStream(spliterator, true)} with the difference that a parallel 129 | * terminal 130 | * operation will be executed in the given {@link ForkJoinPool}. 131 | * 132 | * @param spliterator A {@code Spliterator.OfDouble} describing the stream elements. Must not be {@code null}. 133 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 134 | * @return A parallel {@code double} stream that executes a terminal operation in the given {@link ForkJoinPool}. 135 | * @see StreamSupport#doubleStream(Spliterator.OfDouble, boolean) 136 | */ 137 | public static DoubleStream parallelStream(Spliterator.OfDouble spliterator, ForkJoinPool workerPool) { 138 | requireNonNull(spliterator, "Spliterator must not be null"); 139 | 140 | return new ParallelDoubleStreamSupport(doubleStream(spliterator, true), workerPool); 141 | } 142 | 143 | /** 144 | * Creates a parallel {@code double} stream from the given Spliterator supplier. This operation is 145 | * similar to calling {@code StreamSupport.doubleStream(supplier, characteristics, true)} with the difference that a 146 | * parallel 147 | * terminal 148 | * operation will be executed in the given {@link ForkJoinPool}. 149 | * 150 | * @param supplier A {@code Supplier} of a {@code Spliterator.OfDouble}. Must not be {@code null}. 151 | * @param characteristics Spliterator characteristics of the supplied {@code Spliterator}. The characteristics must 152 | * be equal to {@code supplier.get().characteristics()}, otherwise undefined behavior may occur when terminal 153 | * operation commences. 154 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 155 | * @return A parallel {@code double} stream that executes a terminal operation in the given {@link ForkJoinPool}. 156 | * @see StreamSupport#doubleStream(Supplier, int, boolean) 157 | */ 158 | public static DoubleStream parallelStream(Supplier supplier, int characteristics, ForkJoinPool workerPool) { 159 | requireNonNull(supplier, "Supplier must not be null"); 160 | 161 | return new ParallelDoubleStreamSupport(doubleStream(supplier, characteristics, true), workerPool); 162 | } 163 | 164 | /** 165 | * Creates a parallel {@code double} stream from the given {@link Builder}. This operation is 166 | * similar to calling {@code builder.build().parallel()} with the difference that a parallel 167 | * terminal 168 | * operation will be executed in the given {@link ForkJoinPool}. 169 | * 170 | * @param builder The builder to create the stream from. Must not be {@code null}. 171 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 172 | * @return A parallel {@code double} stream that executes a terminal operation in the given {@link ForkJoinPool}. 173 | * @see DoubleStream#builder() 174 | */ 175 | public static DoubleStream parallelStream(Builder builder, ForkJoinPool workerPool) { 176 | requireNonNull(builder, "Builder must not be null"); 177 | 178 | return new ParallelDoubleStreamSupport(builder.build().parallel(), workerPool); 179 | } 180 | 181 | /** 182 | * Creates a parallel infinite ordered {@code double} stream produced by iterative application of a 183 | * function {@code f} to an initial element {@code seed}. This operation is similar to calling 184 | * {@code DoubleStream.iterate(seed, operator).parallel()} with the difference that a parallel 185 | * terminal 186 | * operation will be executed in the given {@link ForkJoinPool}. 187 | * 188 | * @param seed The initial element. 189 | * @param operator A function to be applied to to the previous element to produce a new element. Must not be {@code null}. 190 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 191 | * @return A parallel {@code double} stream that executes a terminal operation in the given {@link ForkJoinPool}. 192 | * @see DoubleStream#iterate(double, DoubleUnaryOperator) 193 | */ 194 | public static DoubleStream iterate(double seed, DoubleUnaryOperator operator, ForkJoinPool workerPool) { 195 | requireNonNull(operator, "Operator must not be null"); 196 | 197 | return new ParallelDoubleStreamSupport(DoubleStream.iterate(seed, operator).parallel(), workerPool); 198 | } 199 | 200 | /** 201 | * Creates a parallel infinite sequential unordered {@code double} stream where each element is 202 | * generated by the provided {@code DoubleSupplier}. This operation is similar to calling 203 | * {@code DoubleStream.generate(supplier).parallel()} with the difference that a parallel 204 | * terminal 205 | * operation will be executed in the given {@link ForkJoinPool}. 206 | * 207 | * @param supplier The {@code DoubleSupplier} of generated elements. Must not be {@code null}. 208 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 209 | * @return A parallel {@code double} stream that executes a terminal operation in the given {@link ForkJoinPool}. 210 | * @see DoubleStream#generate(DoubleSupplier) 211 | */ 212 | public static DoubleStream generate(DoubleSupplier supplier, ForkJoinPool workerPool) { 213 | requireNonNull(supplier, "Supplier must not be null"); 214 | 215 | return new ParallelDoubleStreamSupport(DoubleStream.generate(supplier).parallel(), workerPool); 216 | } 217 | 218 | /** 219 | * Creates a lazily concatenated parallel {@code double} stream whose elements are all the elements 220 | * of the first stream followed by all the elements of the second stream. This operation is similar to calling 221 | * {@code DoubleStream.concat(a, b).parallel()} with the difference that a parallel 222 | * terminal 223 | * operation will be executed in the given {@link ForkJoinPool}. 224 | * 225 | * @param a The first stream. Must not be {@code null}. 226 | * @param b The second stream. Must not be {@code null}. 227 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 228 | * @return A parallel stream that executes a terminal operation in the given {@link ForkJoinPool}. 229 | * @see DoubleStream#concat(DoubleStream, DoubleStream) 230 | */ 231 | public static DoubleStream concat(DoubleStream a, DoubleStream b, ForkJoinPool workerPool) { 232 | requireNonNull(a, "Stream a must not be null"); 233 | requireNonNull(b, "Stream b must not be null"); 234 | 235 | return new ParallelDoubleStreamSupport(DoubleStream.concat(a, b).parallel(), workerPool); 236 | } 237 | 238 | @Override 239 | public DoubleStream filter(DoublePredicate predicate) { 240 | this.delegate = this.delegate.filter(predicate); 241 | return this; 242 | } 243 | 244 | @Override 245 | public DoubleStream map(DoubleUnaryOperator mapper) { 246 | this.delegate = this.delegate.map(mapper); 247 | return this; 248 | } 249 | 250 | @Override 251 | public Stream mapToObj(DoubleFunction mapper) { 252 | return new ParallelStreamSupport<>(this.delegate.mapToObj(mapper), this.workerPool); 253 | } 254 | 255 | @Override 256 | public IntStream mapToInt(DoubleToIntFunction mapper) { 257 | return new ParallelIntStreamSupport(this.delegate.mapToInt(mapper), this.workerPool); 258 | } 259 | 260 | @Override 261 | public LongStream mapToLong(DoubleToLongFunction mapper) { 262 | return new ParallelLongStreamSupport(this.delegate.mapToLong(mapper), this.workerPool); 263 | } 264 | 265 | @Override 266 | public DoubleStream flatMap(DoubleFunction mapper) { 267 | this.delegate = this.delegate.flatMap(mapper); 268 | return this; 269 | } 270 | 271 | @Override 272 | public DoubleStream distinct() { 273 | this.delegate = this.delegate.distinct(); 274 | return this; 275 | } 276 | 277 | @Override 278 | public DoubleStream sorted() { 279 | this.delegate = this.delegate.sorted(); 280 | return this; 281 | } 282 | 283 | @Override 284 | public DoubleStream peek(DoubleConsumer action) { 285 | this.delegate = this.delegate.peek(action); 286 | return this; 287 | } 288 | 289 | @Override 290 | public DoubleStream limit(long maxSize) { 291 | this.delegate = this.delegate.limit(maxSize); 292 | return this; 293 | } 294 | 295 | @Override 296 | public DoubleStream skip(long n) { 297 | this.delegate = this.delegate.skip(n); 298 | return this; 299 | } 300 | 301 | @Override 302 | public DoubleStream takeWhile(DoublePredicate predicate) { 303 | this.delegate = this.delegate.takeWhile(predicate); 304 | return this; 305 | } 306 | 307 | @Override 308 | public DoubleStream dropWhile(DoublePredicate predicate) { 309 | this.delegate = this.delegate.dropWhile(predicate); 310 | return this; 311 | } 312 | 313 | @Override 314 | public void forEach(DoubleConsumer action) { 315 | execute(() -> this.delegate.forEach(action)); 316 | } 317 | 318 | @Override 319 | public void forEachOrdered(DoubleConsumer action) { 320 | execute(() -> this.delegate.forEachOrdered(action)); 321 | } 322 | 323 | @Override 324 | public double[] toArray() { 325 | return execute(() -> this.delegate.toArray()); 326 | } 327 | 328 | @Override 329 | public double reduce(double identity, DoubleBinaryOperator op) { 330 | return execute(() -> this.delegate.reduce(identity, op)); 331 | } 332 | 333 | @Override 334 | public OptionalDouble reduce(DoubleBinaryOperator op) { 335 | return execute(() -> this.delegate.reduce(op)); 336 | } 337 | 338 | @Override 339 | public R collect(Supplier supplier, ObjDoubleConsumer accumulator, BiConsumer combiner) { 340 | return execute(() -> this.delegate.collect(supplier, accumulator, combiner)); 341 | } 342 | 343 | @Override 344 | public double sum() { 345 | return execute(() -> this.delegate.sum()); 346 | } 347 | 348 | @Override 349 | public OptionalDouble min() { 350 | return execute(() -> this.delegate.min()); 351 | } 352 | 353 | @Override 354 | public OptionalDouble max() { 355 | return execute(() -> this.delegate.max()); 356 | } 357 | 358 | @Override 359 | public long count() { 360 | return execute(() -> this.delegate.count()); 361 | } 362 | 363 | @Override 364 | public OptionalDouble average() { 365 | return execute(() -> this.delegate.average()); 366 | } 367 | 368 | @Override 369 | public DoubleSummaryStatistics summaryStatistics() { 370 | return execute(() -> this.delegate.summaryStatistics()); 371 | } 372 | 373 | @Override 374 | public boolean anyMatch(DoublePredicate predicate) { 375 | return execute(() -> this.delegate.anyMatch(predicate)); 376 | } 377 | 378 | @Override 379 | public boolean allMatch(DoublePredicate predicate) { 380 | return execute(() -> this.delegate.allMatch(predicate)); 381 | } 382 | 383 | @Override 384 | public boolean noneMatch(DoublePredicate predicate) { 385 | return execute(() -> this.delegate.noneMatch(predicate)); 386 | } 387 | 388 | @Override 389 | public OptionalDouble findFirst() { 390 | return execute(() -> this.delegate.findFirst()); 391 | } 392 | 393 | @Override 394 | public OptionalDouble findAny() { 395 | return execute(() -> this.delegate.findAny()); 396 | } 397 | 398 | @Override 399 | public Stream boxed() { 400 | return new ParallelStreamSupport<>(this.delegate.boxed(), this.workerPool); 401 | } 402 | 403 | @Override 404 | public OfDouble iterator() { 405 | return this.delegate.iterator(); 406 | } 407 | 408 | @Override 409 | public java.util.Spliterator.OfDouble spliterator() { 410 | return this.delegate.spliterator(); 411 | } 412 | 413 | } 414 | -------------------------------------------------------------------------------- /src/main/java/com/github/ferstl/streams/ParallelIntStreamSupport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Stefan Ferstl 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.github.ferstl.streams; 23 | 24 | import java.util.Arrays; 25 | import java.util.IntSummaryStatistics; 26 | import java.util.OptionalDouble; 27 | import java.util.OptionalInt; 28 | import java.util.PrimitiveIterator.OfInt; 29 | import java.util.Spliterator; 30 | import java.util.concurrent.ForkJoinPool; 31 | import java.util.concurrent.ForkJoinTask; 32 | import java.util.function.BiConsumer; 33 | import java.util.function.IntBinaryOperator; 34 | import java.util.function.IntConsumer; 35 | import java.util.function.IntFunction; 36 | import java.util.function.IntPredicate; 37 | import java.util.function.IntSupplier; 38 | import java.util.function.IntToDoubleFunction; 39 | import java.util.function.IntToLongFunction; 40 | import java.util.function.IntUnaryOperator; 41 | import java.util.function.ObjIntConsumer; 42 | import java.util.function.Supplier; 43 | import java.util.stream.DoubleStream; 44 | import java.util.stream.IntStream; 45 | import java.util.stream.LongStream; 46 | import java.util.stream.Stream; 47 | import java.util.stream.StreamSupport; 48 | import static java.util.Arrays.stream; 49 | import static java.util.Objects.requireNonNull; 50 | import static java.util.stream.StreamSupport.intStream; 51 | 52 | 53 | /** 54 | *

55 | * An implementation of {@link IntStream} which uses a custom {@link ForkJoinPool} for parallel aggregate operations. 56 | * This is the {@code int} primitive specialization of {@link ParallelStreamSupport}. 57 | *

58 | * The following example illustrates an aggregate operation using {@link ParallelStreamSupport} and 59 | * {@link ParallelIntStreamSupport} with a custom {@link ForkJoinPool}, computing the sum of the weights of the red 60 | * widgets: 61 | *

 62 |  * ForkJoinPool pool = new ForkJoinPool();
 63 |  * int sum = ParallelStreamSupport.parallelStream(widgets, pool)
 64 |  *     .filter(w -> w.getColor() == RED)
 65 |  *     .mapToInt(w -> w.getWeight())
 66 |  *     .sum();
 67 |  * 
68 | *

69 | * In case this stream is configured for parallel execution, i.e. {@link #isParallel()} returns {@code true}, a 70 | * terminal 71 | * operation will be executed as {@link ForkJoinTask} in the custom {@link ForkJoinPool}. Otherwise it will be 72 | * executed in the calling thread. 73 | *

74 | * This implementation offers various factory methods which are based on: 75 | *
    76 | *
  • The static factory methods of {@link IntStream}, which are meaningful for parallel streams
  • 77 | *
  • {@link Arrays#stream(int[])}
  • 78 | *
  • {@link StreamSupport#intStream(Spliterator.OfInt, boolean)}
  • 79 | *
  • {@link StreamSupport#intStream(Supplier, int, boolean)}
  • 80 | *
81 | * 82 | * @apiNote

83 | * Internally, this stream wraps an {@code int} stream which is initially created in one of the static factory methods. 84 | * Whenever a non-terminal operation is called the underlying stream will be replaced with the result of calling the 85 | * same method on that stream. The return value of these operations is always this stream or, in case of operations 86 | * that return a different type of stream, one of {@link ParallelStreamSupport}, {@link ParallelLongStreamSupport} or 87 | * {@link ParallelDoubleStreamSupport}. 88 | *

89 | *

90 | * Although each factory method returns a parallel stream, calling {@link #sequential()} is still possible and leads to 91 | * sequential execution of a terminal operation within the calling thread. 92 | *

93 | * @implNote

94 | * See the class documentation for {@link Stream} and the package documentation for 95 | * java.util.stream for 96 | * additional specification. 97 | *

98 | */ 99 | public class ParallelIntStreamSupport extends AbstractParallelStreamSupport implements IntStream { 100 | 101 | /** 102 | * Constructor for internal use within this package only. 103 | * 104 | * @param delegate Stream to delegate each operation. 105 | * @param workerPool Worker pool for executing terminal operations in parallel. Must not be {@code null}. 106 | */ 107 | ParallelIntStreamSupport(IntStream delegate, ForkJoinPool workerPool) { 108 | super(delegate, workerPool); 109 | } 110 | 111 | /** 112 | * Creates a parallel {@code int} stream from the given Array. This operation is similar to calling 113 | * {@code Arrays.stream(array).parallel()} with the difference that a parallel 114 | * terminal 115 | * operation will be executed in the given {@link ForkJoinPool}. 116 | * 117 | * @param array Array to create the parallel stream from. Must not be {@code null}. 118 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 119 | * @return A parallel {@code int} stream that executes a terminal operation in the given {@link ForkJoinPool}. 120 | * @see Arrays#stream(int[]) 121 | */ 122 | public static IntStream parallelStream(int[] array, ForkJoinPool workerPool) { 123 | requireNonNull(array, "Array must not be null"); 124 | 125 | return new ParallelIntStreamSupport(stream(array).parallel(), workerPool); 126 | } 127 | 128 | /** 129 | * Creates a parallel {@code int} stream from the given Spliterator. This operation is similar to 130 | * calling {@code StreamSupport.intStream(spliterator, true)} with the difference that a parallel 131 | * terminal 132 | * operation will be executed in the given {@link ForkJoinPool}. 133 | * 134 | * @param spliterator A {@code Spliterator.OfInt} describing the stream elements. Must not be {@code null}. 135 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 136 | * @return A parallel {@code int} stream that executes a terminal operation in the given {@link ForkJoinPool}. 137 | * @see StreamSupport#intStream(Spliterator.OfInt, boolean) 138 | */ 139 | public static IntStream parallelStream(Spliterator.OfInt spliterator, ForkJoinPool workerPool) { 140 | requireNonNull(spliterator, "Spliterator must not be null"); 141 | 142 | return new ParallelIntStreamSupport(intStream(spliterator, true), workerPool); 143 | } 144 | 145 | /** 146 | * Creates a parallel {@code int} stream from the given Spliterator supplier. This operation is 147 | * similar to calling {@code StreamSupport.intStream(supplier, characteristics, true)} with the difference that a 148 | * parallel 149 | * terminal 150 | * operation will be executed in the given {@link ForkJoinPool}. 151 | * 152 | * @param supplier A {@code Supplier} of a {@code Spliterator.OfInt}. Must not be {@code null}. 153 | * @param characteristics Spliterator characteristics of the supplied {@code Spliterator}. The characteristics must 154 | * be equal to {@code supplier.get().characteristics()}, otherwise undefined behavior may occur when terminal 155 | * operation commences. 156 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 157 | * @return A parallel {@code int} stream that executes a terminal operation in the given {@link ForkJoinPool}. 158 | * @see StreamSupport#intStream(Supplier, int, boolean) 159 | */ 160 | public static IntStream parallelStream(Supplier supplier, int characteristics, ForkJoinPool workerPool) { 161 | requireNonNull(supplier, "Supplier must not be null"); 162 | 163 | return new ParallelIntStreamSupport(intStream(supplier, characteristics, true), workerPool); 164 | } 165 | 166 | /** 167 | * Creates a parallel {@code int} stream from the given {@link Builder}. This operation is similar 168 | * to calling {@code builder.build().parallel()} with the difference that a parallel 169 | * terminal 170 | * operation will be executed in the given {@link ForkJoinPool}. 171 | * 172 | * @param builder The builder to create the stream from. Must not be {@code null}. 173 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 174 | * @return A parallel {@code int} stream that executes a terminal operation in the given {@link ForkJoinPool}. 175 | * @see IntStream#builder() 176 | */ 177 | public static IntStream parallelStream(Builder builder, ForkJoinPool workerPool) { 178 | requireNonNull(builder, "Builder must not be null"); 179 | 180 | return new ParallelIntStreamSupport(builder.build().parallel(), workerPool); 181 | } 182 | 183 | /** 184 | * Creates a parallel infinite ordered {@code int} stream produced by iterative application of a 185 | * function {@code f} to an initial element {@code seed}. This operation is similar to calling 186 | * {@code IntStream.iterate(seed, operator).parallel()} with the difference that a parallel 187 | * terminal 188 | * operation will be executed in the given {@link ForkJoinPool}. 189 | * 190 | * @param seed The initial element. 191 | * @param operator A function to be applied to to the previous element to produce a new element. Must not be {@code null}. 192 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 193 | * @return A parallel {@code int} stream that executes a terminal operation in the given {@link ForkJoinPool}. 194 | * @see IntStream#iterate(int, IntUnaryOperator) 195 | */ 196 | public static IntStream iterate(int seed, IntUnaryOperator operator, ForkJoinPool workerPool) { 197 | requireNonNull(operator, "Operator must not be null"); 198 | 199 | return new ParallelIntStreamSupport(IntStream.iterate(seed, operator).parallel(), workerPool); 200 | } 201 | 202 | /** 203 | * Creates a parallel infinite sequential unordered {@code int} stream where each element is 204 | * generated by the provided {@code IntSupplier}. This operation is similar to calling 205 | * {@code IntStream.generate(supplier).parallel()} with the difference that a parallel 206 | * terminal 207 | * operation will be executed in the given {@link ForkJoinPool}. 208 | * 209 | * @param supplier The {@code IntSupplier} of generated elements. Must not be {@code null}. 210 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 211 | * @return A parallel {@code int} stream that executes a terminal operation in the given {@link ForkJoinPool}. 212 | * @see IntStream#generate(IntSupplier) 213 | */ 214 | public static IntStream generate(IntSupplier supplier, ForkJoinPool workerPool) { 215 | requireNonNull(supplier, "Supplier must not be null"); 216 | 217 | return new ParallelIntStreamSupport(IntStream.generate(supplier).parallel(), workerPool); 218 | } 219 | 220 | /** 221 | * Creates a parallel ordered {@code int} stream from {@code startInclusive} (inclusive) to 222 | * {@code endExclusive} (exclusive) by an incremental step of {@code 1}. This operation is similar to calling 223 | * {@code IntStream.range(startInclusive, endExclusive).parallel()} with the difference that a parallel 224 | * terminal 225 | * operation will be executed in the given {@link ForkJoinPool}. 226 | * 227 | * @param startInclusive the (inclusive) initial value 228 | * @param endExclusive the exclusive upper bound 229 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 230 | * @return A parallel {@code int} stream that executes a terminal operation in the given {@link ForkJoinPool} for the 231 | * range of {@code int} elements. 232 | * @see IntStream#range(int, int) 233 | */ 234 | public static IntStream range(int startInclusive, int endExclusive, ForkJoinPool workerPool) { 235 | return new ParallelIntStreamSupport(IntStream.range(startInclusive, endExclusive).parallel(), workerPool); 236 | } 237 | 238 | /** 239 | * Creates a parallel ordered {@code int} stream from {@code startInclusive} (inclusive) to 240 | * {@code endInclusive} (inclusive) by an incremental step of {@code 1}. This operation is similar to calling 241 | * {@code IntStream.rangeClosed(startInclusive, endInclusive).parallel()} with the difference that a parallel 242 | * terminal 243 | * operation will be executed in the given {@link ForkJoinPool}. 244 | * 245 | * @param startInclusive the (inclusive) initial value 246 | * @param endInclusive the inclusive upper bound 247 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 248 | * @return A parallel {@code int} stream that executes a terminal operation in the given {@link ForkJoinPool} for the 249 | * range of {@code int} elements. 250 | * @see IntStream#rangeClosed(int, int) 251 | */ 252 | public static IntStream rangeClosed(int startInclusive, int endInclusive, ForkJoinPool workerPool) { 253 | return new ParallelIntStreamSupport(IntStream.rangeClosed(startInclusive, endInclusive).parallel(), workerPool); 254 | } 255 | 256 | /** 257 | * Creates a lazily concatenated parallel {@code int} stream whose elements are all the elements of 258 | * the first stream followed by all the elements of the second stream. This operation is similar to calling 259 | * {@code IntStream.concat(a, b).parallel()} with the difference that a parallel 260 | * terminal 261 | * operation will be executed in the given {@link ForkJoinPool}. 262 | * 263 | * @param a The first stream. Must not be {@code null}. 264 | * @param b The second stream. Must not be {@code null}. 265 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 266 | * @return A parallel stream that executes a terminal operation in the given {@link ForkJoinPool}. 267 | * @see IntStream#concat(IntStream, IntStream) 268 | */ 269 | public static IntStream concat(IntStream a, IntStream b, ForkJoinPool workerPool) { 270 | requireNonNull(a, "Stream a must not be null"); 271 | requireNonNull(b, "Stream b must not be null"); 272 | 273 | return new ParallelIntStreamSupport(IntStream.concat(a, b).parallel(), workerPool); 274 | } 275 | 276 | @Override 277 | public IntStream filter(IntPredicate predicate) { 278 | this.delegate = this.delegate.filter(predicate); 279 | return this; 280 | } 281 | 282 | @Override 283 | public IntStream map(IntUnaryOperator mapper) { 284 | this.delegate = this.delegate.map(mapper); 285 | return this; 286 | } 287 | 288 | @Override 289 | public Stream mapToObj(IntFunction mapper) { 290 | return new ParallelStreamSupport(this.delegate.mapToObj(mapper), this.workerPool); 291 | } 292 | 293 | @Override 294 | public LongStream mapToLong(IntToLongFunction mapper) { 295 | return new ParallelLongStreamSupport(this.delegate.mapToLong(mapper), this.workerPool); 296 | } 297 | 298 | @Override 299 | public DoubleStream mapToDouble(IntToDoubleFunction mapper) { 300 | return new ParallelDoubleStreamSupport(this.delegate.mapToDouble(mapper), this.workerPool); 301 | } 302 | 303 | @Override 304 | public IntStream flatMap(IntFunction mapper) { 305 | this.delegate = this.delegate.flatMap(mapper); 306 | return this; 307 | } 308 | 309 | @Override 310 | public IntStream distinct() { 311 | this.delegate = this.delegate.distinct(); 312 | return this; 313 | } 314 | 315 | @Override 316 | public IntStream sorted() { 317 | this.delegate = this.delegate.sorted(); 318 | return this; 319 | } 320 | 321 | @Override 322 | public IntStream peek(IntConsumer action) { 323 | this.delegate = this.delegate.peek(action); 324 | return this; 325 | } 326 | 327 | @Override 328 | public IntStream limit(long maxSize) { 329 | this.delegate = this.delegate.limit(maxSize); 330 | return this; 331 | } 332 | 333 | @Override 334 | public IntStream skip(long n) { 335 | this.delegate = this.delegate.skip(n); 336 | return this; 337 | } 338 | 339 | @Override 340 | public IntStream takeWhile(IntPredicate predicate) { 341 | this.delegate = this.delegate.takeWhile(predicate); 342 | return this; 343 | } 344 | 345 | @Override 346 | public IntStream dropWhile(IntPredicate predicate) { 347 | this.delegate = this.delegate.dropWhile(predicate); 348 | return this; 349 | } 350 | 351 | @Override 352 | public void forEach(IntConsumer action) { 353 | execute(() -> this.delegate.forEach(action)); 354 | } 355 | 356 | @Override 357 | public void forEachOrdered(IntConsumer action) { 358 | execute(() -> this.delegate.forEachOrdered(action)); 359 | } 360 | 361 | @Override 362 | public int[] toArray() { 363 | return execute(() -> this.delegate.toArray()); 364 | } 365 | 366 | @Override 367 | public int reduce(int identity, IntBinaryOperator op) { 368 | return execute(() -> this.delegate.reduce(identity, op)); 369 | } 370 | 371 | @Override 372 | public OptionalInt reduce(IntBinaryOperator op) { 373 | return execute(() -> this.delegate.reduce(op)); 374 | } 375 | 376 | @Override 377 | public R collect(Supplier supplier, ObjIntConsumer accumulator, BiConsumer combiner) { 378 | return execute(() -> this.delegate.collect(supplier, accumulator, combiner)); 379 | } 380 | 381 | @Override 382 | public int sum() { 383 | return execute(() -> this.delegate.sum()); 384 | } 385 | 386 | @Override 387 | public OptionalInt min() { 388 | return execute(() -> this.delegate.min()); 389 | } 390 | 391 | @Override 392 | public OptionalInt max() { 393 | return execute(() -> this.delegate.max()); 394 | } 395 | 396 | @Override 397 | public long count() { 398 | return execute(() -> this.delegate.count()); 399 | } 400 | 401 | @Override 402 | public OptionalDouble average() { 403 | return execute(() -> this.delegate.average()); 404 | } 405 | 406 | @Override 407 | public IntSummaryStatistics summaryStatistics() { 408 | return execute(() -> this.delegate.summaryStatistics()); 409 | } 410 | 411 | @Override 412 | public boolean anyMatch(IntPredicate predicate) { 413 | return execute(() -> this.delegate.anyMatch(predicate)); 414 | } 415 | 416 | @Override 417 | public boolean allMatch(IntPredicate predicate) { 418 | return execute(() -> this.delegate.allMatch(predicate)); 419 | } 420 | 421 | @Override 422 | public boolean noneMatch(IntPredicate predicate) { 423 | return execute(() -> this.delegate.noneMatch(predicate)); 424 | } 425 | 426 | @Override 427 | public OptionalInt findFirst() { 428 | return execute(() -> this.delegate.findFirst()); 429 | } 430 | 431 | @Override 432 | public OptionalInt findAny() { 433 | return execute(() -> this.delegate.findAny()); 434 | } 435 | 436 | @Override 437 | public LongStream asLongStream() { 438 | return new ParallelLongStreamSupport(this.delegate.asLongStream(), this.workerPool); 439 | } 440 | 441 | @Override 442 | public DoubleStream asDoubleStream() { 443 | return new ParallelDoubleStreamSupport(this.delegate.asDoubleStream(), this.workerPool); 444 | } 445 | 446 | @Override 447 | public Stream boxed() { 448 | return new ParallelStreamSupport<>(this.delegate.boxed(), this.workerPool); 449 | } 450 | 451 | @Override 452 | public OfInt iterator() { 453 | return this.delegate.iterator(); 454 | } 455 | 456 | @Override 457 | public java.util.Spliterator.OfInt spliterator() { 458 | return this.delegate.spliterator(); 459 | } 460 | } 461 | -------------------------------------------------------------------------------- /src/main/java/com/github/ferstl/streams/ParallelLongStreamSupport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Stefan Ferstl 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.github.ferstl.streams; 23 | 24 | import java.util.Arrays; 25 | import java.util.LongSummaryStatistics; 26 | import java.util.OptionalDouble; 27 | import java.util.OptionalLong; 28 | import java.util.PrimitiveIterator.OfLong; 29 | import java.util.Spliterator; 30 | import java.util.concurrent.ForkJoinPool; 31 | import java.util.concurrent.ForkJoinTask; 32 | import java.util.function.BiConsumer; 33 | import java.util.function.LongBinaryOperator; 34 | import java.util.function.LongConsumer; 35 | import java.util.function.LongFunction; 36 | import java.util.function.LongPredicate; 37 | import java.util.function.LongSupplier; 38 | import java.util.function.LongToDoubleFunction; 39 | import java.util.function.LongToIntFunction; 40 | import java.util.function.LongUnaryOperator; 41 | import java.util.function.ObjLongConsumer; 42 | import java.util.function.Supplier; 43 | import java.util.stream.DoubleStream; 44 | import java.util.stream.IntStream; 45 | import java.util.stream.LongStream; 46 | import java.util.stream.Stream; 47 | import java.util.stream.StreamSupport; 48 | import static java.util.Arrays.stream; 49 | import static java.util.Objects.requireNonNull; 50 | import static java.util.stream.StreamSupport.longStream; 51 | 52 | /** 53 | *

54 | * An implementation of {@link LongStream} which uses a custom {@link ForkJoinPool} for parallel aggregate operations. 55 | * This is the {@code long} primitive specialization of {@link ParallelStreamSupport}. 56 | *

57 | * The following example illustrates an aggregate operation using {@link ParallelStreamSupport} and 58 | * {@link ParallelLongStreamSupport} with a custom {@link ForkJoinPool}, computing the sum of the weights of the red 59 | * widgets: 60 | *

 61 |  * ForkJoinPool pool = new ForkJoinPool();
 62 |  * long sum = ParallelStreamSupport.parallelStream(widgets, pool)
 63 |  *     .filter(w -> w.getColor() == RED)
 64 |  *     .mapToLong(w -> w.getWeight())
 65 |  *     .sum();
 66 |  * 
67 | *

68 | * In case this stream is configured for parallel execution, i.e. {@link #isParallel()} returns {@code true}, a 69 | * terminal 70 | * operation will be executed as {@link ForkJoinTask} in the custom {@link ForkJoinPool}. Otherwise it will be 71 | * executed in the calling thread. 72 | *

73 | * This implementation offers various factory methods which are based on: 74 | *
    75 | *
  • The static factory methods of {@link LongStream}, which are meaningful for parallel streams
  • 76 | *
  • {@link Arrays#stream(long[])}
  • 77 | *
  • {@link StreamSupport#longStream(Spliterator.OfLong, boolean)}
  • 78 | *
  • {@link StreamSupport#longStream(Supplier, int, boolean)}
  • 79 | *
80 | * 81 | * @apiNote

82 | * Internally, this stream wraps a {@code long} stream which is initially created in one of the static factory methods. 83 | * Whenever a non-terminal operation is called the underlying stream will be replaced with the result of calling the 84 | * same method on that stream. The return value of these operations is always this stream or, in case of operations 85 | * that return a different type of stream, one of {@link ParallelStreamSupport}, {@link ParallelIntStreamSupport} or 86 | * {@link ParallelDoubleStreamSupport}. 87 | *

88 | *

89 | * Although each factory method returns a parallel stream, calling {@link #sequential()} is still possible and leads to 90 | * sequential execution of a terminal operation within the calling thread. 91 | *

92 | * @implNote

93 | * See the class documentation for {@link Stream} and the package documentation for 94 | * java.util.stream for 95 | * additional specification. 96 | *

97 | */ 98 | public class ParallelLongStreamSupport extends AbstractParallelStreamSupport implements LongStream { 99 | 100 | /** 101 | * Constructor for internal use within this package only. 102 | * 103 | * @param delegate Stream to delegate each operation. 104 | * @param workerPool Worker pool for executing terminal operations in parallel. Must not be {@code null}. 105 | */ 106 | ParallelLongStreamSupport(LongStream delegate, ForkJoinPool workerPool) { 107 | super(delegate, workerPool); 108 | } 109 | 110 | /** 111 | * Creates a parallel {@code long} stream from the given Array. This operation is similar to calling 112 | * {@code Arrays.stream(array).parallel()} with the difference that a parallel 113 | * terminal 114 | * operation will be executed in the given {@link ForkJoinPool}. 115 | * 116 | * @param array Array to create the parallel stream from. Must not be {@code null}. 117 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 118 | * @return A parallel {@code long} stream that executes a terminal operation in the given {@link ForkJoinPool}. 119 | * @see Arrays#stream(long[]) 120 | */ 121 | public static LongStream parallelStream(long[] array, ForkJoinPool workerPool) { 122 | requireNonNull(array, "Array must not be null"); 123 | 124 | return new ParallelLongStreamSupport(stream(array).parallel(), workerPool); 125 | } 126 | 127 | /** 128 | * Creates a parallel {@code long} stream from the given Spliterator. This operation is similar to 129 | * calling {@code StreamSupport.longStream(spliterator, true)} with the difference that a parallel 130 | * terminal 131 | * operation will be executed in the given {@link ForkJoinPool}. 132 | * 133 | * @param spliterator A {@code Spliterator.OfLong} describing the stream elements. Must not be {@code null}. 134 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 135 | * @return A parallel {@code long} stream that executes a terminal operation in the given {@link ForkJoinPool}. 136 | * @see StreamSupport#longStream(Spliterator.OfLong, boolean) 137 | */ 138 | public static LongStream parallelStream(Spliterator.OfLong spliterator, ForkJoinPool workerPool) { 139 | requireNonNull(spliterator, "Spliterator must not be null"); 140 | 141 | return new ParallelLongStreamSupport(longStream(spliterator, true), workerPool); 142 | } 143 | 144 | /** 145 | * Creates a parallel {@code long} stream from the given Spliterator supplier. This operation is 146 | * similar to calling {@code StreamSupport.longStream(supplier, characteristics, true)} with the difference that a 147 | * parallel 148 | * terminal 149 | * operation will be executed in the given {@link ForkJoinPool}. 150 | * 151 | * @param supplier A {@code Supplier} of a {@code Spliterator.OfLong}. Must not be {@code null}. 152 | * @param characteristics Spliterator characteristics of the supplied {@code Spliterator}. The characteristics must 153 | * be equal to {@code supplier.get().characteristics()}, otherwise undefined behavior may occur when terminal 154 | * operation commences. 155 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 156 | * @return A parallel {@code long} stream that executes a terminal operation in the given {@link ForkJoinPool}. 157 | * @see StreamSupport#longStream(Supplier, int, boolean) 158 | */ 159 | public static LongStream parallelStream(Supplier supplier, int characteristics, ForkJoinPool workerPool) { 160 | requireNonNull(supplier, "Supplier must not be null"); 161 | 162 | return new ParallelLongStreamSupport(longStream(supplier, characteristics, true), workerPool); 163 | } 164 | 165 | /** 166 | * Creates a parallel {@code long} stream from the given {@link Builder}. This operation is similar 167 | * to calling {@code builder.build().parallel()} with the difference that a parallel 168 | * terminal 169 | * operation will be executed in the given {@link ForkJoinPool}. 170 | * 171 | * @param builder The builder to create the stream from. Must not be {@code null}. 172 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 173 | * @return A parallel {@code long} stream that executes a terminal operation in the given {@link ForkJoinPool}. 174 | * builder() 175 | */ 176 | public static LongStream parallelStream(Builder builder, ForkJoinPool workerPool) { 177 | requireNonNull(builder, "Builder must not be null"); 178 | 179 | return new ParallelLongStreamSupport(builder.build().parallel(), workerPool); 180 | } 181 | 182 | /** 183 | * Creates a parallel infinite ordered {@code long} stream produced by iterative application of a 184 | * function {@code f} to an initial element {@code seed}. This operation is similar to calling 185 | * {@code LongStream.iterate(seed, operator).parallel()} with the difference that a parallel 186 | * terminal 187 | * operation will be executed in the given {@link ForkJoinPool}. 188 | * 189 | * @param seed The initial element. 190 | * @param operator A function to be applied to to the previous element to produce a new element. Must not be {@code null}. 191 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 192 | * @return A parallel {@code long} stream that executes a terminal operation in the given {@link ForkJoinPool}. 193 | * @see LongStream#iterate(long, LongUnaryOperator) 194 | */ 195 | public static LongStream iterate(long seed, LongUnaryOperator operator, ForkJoinPool workerPool) { 196 | requireNonNull(operator, "Operator must not be null"); 197 | 198 | return new ParallelLongStreamSupport(LongStream.iterate(seed, operator).parallel(), workerPool); 199 | } 200 | 201 | /** 202 | * Creates a parallel infinite sequential unordered {@code long} stream where each element is 203 | * generated by the provided {@code LongSupplier}. This operation is similar to calling 204 | * {@code LongStream.generate(supplier).parallel()} with the difference that a parallel 205 | * terminal 206 | * operation will be executed in the given {@link ForkJoinPool}. 207 | * 208 | * @param supplier The {@code LongSupplier} of generated elements. Must not be {@code null}. 209 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 210 | * @return A parallel {@code long} stream that executes a terminal operation in the given {@link ForkJoinPool}. 211 | * @see LongStream#generate(LongSupplier) 212 | */ 213 | public static LongStream generate(LongSupplier supplier, ForkJoinPool workerPool) { 214 | requireNonNull(supplier, "Supplier must not be null"); 215 | 216 | return new ParallelLongStreamSupport(LongStream.generate(supplier).parallel(), workerPool); 217 | } 218 | 219 | /** 220 | * Creates a parallel ordered {@code long} stream from {@code startInclusive} (inclusive) to 221 | * {@code endExclusive} (exclusive) by an incremental step of {@code 1}. This operation is similar to calling 222 | * {@code LongStream.range(startInclusive, endExclusive).parallel()} with the difference that a parallel 223 | * terminal 224 | * operation will be executed in the given {@link ForkJoinPool}. 225 | * 226 | * @param startInclusive the (inclusive) initial value 227 | * @param endExclusive the exclusive upper bound 228 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 229 | * @return A parallel {@code long} stream that executes a terminal operation in the given {@link ForkJoinPool} for 230 | * the range of {@code long} elements. 231 | * @see LongStream#range(long, long) 232 | */ 233 | public static LongStream range(long startInclusive, long endExclusive, ForkJoinPool workerPool) { 234 | return new ParallelLongStreamSupport(LongStream.range(startInclusive, endExclusive).parallel(), workerPool); 235 | } 236 | 237 | /** 238 | * Creates a parallel ordered {@code long} stream from {@code startInclusive} (inclusive) to 239 | * {@code endInclusive} (inclusive) by an incremental step of {@code 1}. This operation is similar to calling 240 | * {@code LongStream.rangeClosed(startInclusive, endInclusive).parallel()} with the difference that a parallel 241 | * terminal 242 | * operation will be executed in the given {@link ForkJoinPool}. 243 | * 244 | * @param startInclusive the (inclusive) initial value 245 | * @param endInclusive the inclusive upper bound 246 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 247 | * @return A parallel {@code long} stream that executes a terminal operation in the given {@link ForkJoinPool} for 248 | * the range of {@code long} elements. 249 | * @see LongStream#rangeClosed(long, long) 250 | */ 251 | public static LongStream rangeClosed(long startInclusive, long endInclusive, ForkJoinPool workerPool) { 252 | return new ParallelLongStreamSupport(LongStream.rangeClosed(startInclusive, endInclusive).parallel(), workerPool); 253 | } 254 | 255 | /** 256 | * Creates a lazily concatenated parallel {@code long} stream whose elements are all the elements of 257 | * the first stream followed by all the elements of the second stream. This operation is similar to calling 258 | * {@code LongStream.concat(a, b).parallel()} with the difference that a parallel 259 | * terminal 260 | * operation will be executed in the given {@link ForkJoinPool}. 261 | * 262 | * @param a The first stream. Must not be {@code null}. 263 | * @param b The second stream. Must not be {@code null}. 264 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 265 | * @return A parallel stream that executes a terminal operation in the given {@link ForkJoinPool}. 266 | * @see LongStream#concat(LongStream, LongStream) 267 | */ 268 | public static LongStream concat(LongStream a, LongStream b, ForkJoinPool workerPool) { 269 | requireNonNull(a, "Stream a must not be null"); 270 | requireNonNull(b, "Stream b must not be null"); 271 | 272 | return new ParallelLongStreamSupport(LongStream.concat(a, b).parallel(), workerPool); 273 | } 274 | 275 | @Override 276 | public LongStream filter(LongPredicate predicate) { 277 | this.delegate = this.delegate.filter(predicate); 278 | return this; 279 | } 280 | 281 | @Override 282 | public LongStream map(LongUnaryOperator mapper) { 283 | this.delegate = this.delegate.map(mapper); 284 | return this; 285 | } 286 | 287 | @Override 288 | public Stream mapToObj(LongFunction mapper) { 289 | return new ParallelStreamSupport<>(this.delegate.mapToObj(mapper), this.workerPool); 290 | } 291 | 292 | @Override 293 | public IntStream mapToInt(LongToIntFunction mapper) { 294 | return new ParallelIntStreamSupport(this.delegate.mapToInt(mapper), this.workerPool); 295 | } 296 | 297 | @Override 298 | public DoubleStream mapToDouble(LongToDoubleFunction mapper) { 299 | return new ParallelDoubleStreamSupport(this.delegate.mapToDouble(mapper), this.workerPool); 300 | } 301 | 302 | @Override 303 | public LongStream flatMap(LongFunction mapper) { 304 | this.delegate = this.delegate.flatMap(mapper); 305 | return this; 306 | } 307 | 308 | @Override 309 | public LongStream distinct() { 310 | this.delegate = this.delegate.distinct(); 311 | return this; 312 | } 313 | 314 | @Override 315 | public LongStream sorted() { 316 | this.delegate = this.delegate.sorted(); 317 | return this; 318 | } 319 | 320 | @Override 321 | public LongStream peek(LongConsumer action) { 322 | this.delegate = this.delegate.peek(action); 323 | return this; 324 | } 325 | 326 | @Override 327 | public LongStream limit(long maxSize) { 328 | this.delegate = this.delegate.limit(maxSize); 329 | return this; 330 | } 331 | 332 | @Override 333 | public LongStream skip(long n) { 334 | this.delegate = this.delegate.skip(n); 335 | return this; 336 | } 337 | 338 | @Override 339 | public LongStream takeWhile(LongPredicate predicate) { 340 | this.delegate = this.delegate.takeWhile(predicate); 341 | return this; 342 | } 343 | 344 | @Override 345 | public LongStream dropWhile(LongPredicate predicate) { 346 | this.delegate = this.delegate.dropWhile(predicate); 347 | return this; 348 | } 349 | 350 | @Override 351 | public void forEach(LongConsumer action) { 352 | execute(() -> this.delegate.forEach(action)); 353 | } 354 | 355 | @Override 356 | public void forEachOrdered(LongConsumer action) { 357 | execute(() -> this.delegate.forEachOrdered(action)); 358 | } 359 | 360 | @Override 361 | public long[] toArray() { 362 | return execute(() -> this.delegate.toArray()); 363 | } 364 | 365 | @Override 366 | public long reduce(long identity, LongBinaryOperator op) { 367 | return execute(() -> this.delegate.reduce(identity, op)); 368 | } 369 | 370 | @Override 371 | public OptionalLong reduce(LongBinaryOperator op) { 372 | return execute(() -> this.delegate.reduce(op)); 373 | } 374 | 375 | @Override 376 | public R collect(Supplier supplier, ObjLongConsumer accumulator, BiConsumer combiner) { 377 | return execute(() -> this.delegate.collect(supplier, accumulator, combiner)); 378 | } 379 | 380 | @Override 381 | public long sum() { 382 | return execute(() -> this.delegate.sum()); 383 | } 384 | 385 | @Override 386 | public OptionalLong min() { 387 | return execute(() -> this.delegate.min()); 388 | } 389 | 390 | @Override 391 | public OptionalLong max() { 392 | return execute(() -> this.delegate.max()); 393 | } 394 | 395 | @Override 396 | public long count() { 397 | return execute(() -> this.delegate.count()); 398 | } 399 | 400 | @Override 401 | public OptionalDouble average() { 402 | return execute(() -> this.delegate.average()); 403 | } 404 | 405 | @Override 406 | public LongSummaryStatistics summaryStatistics() { 407 | return execute(() -> this.delegate.summaryStatistics()); 408 | } 409 | 410 | @Override 411 | public boolean anyMatch(LongPredicate predicate) { 412 | return execute(() -> this.delegate.anyMatch(predicate)); 413 | } 414 | 415 | @Override 416 | public boolean allMatch(LongPredicate predicate) { 417 | return execute(() -> this.delegate.allMatch(predicate)); 418 | } 419 | 420 | @Override 421 | public boolean noneMatch(LongPredicate predicate) { 422 | return execute(() -> this.delegate.noneMatch(predicate)); 423 | } 424 | 425 | @Override 426 | public OptionalLong findFirst() { 427 | return execute(() -> this.delegate.findFirst()); 428 | } 429 | 430 | @Override 431 | public OptionalLong findAny() { 432 | return execute(() -> this.delegate.findAny()); 433 | } 434 | 435 | @Override 436 | public DoubleStream asDoubleStream() { 437 | return new ParallelDoubleStreamSupport(this.delegate.asDoubleStream(), this.workerPool); 438 | } 439 | 440 | @Override 441 | public Stream boxed() { 442 | return new ParallelStreamSupport<>(this.delegate.boxed(), this.workerPool); 443 | } 444 | 445 | @Override 446 | public OfLong iterator() { 447 | return this.delegate.iterator(); 448 | } 449 | 450 | @Override 451 | public java.util.Spliterator.OfLong spliterator() { 452 | return this.delegate.spliterator(); 453 | } 454 | } 455 | -------------------------------------------------------------------------------- /src/main/java/com/github/ferstl/streams/ParallelStreamSupport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Stefan Ferstl 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.github.ferstl.streams; 23 | 24 | import java.util.Arrays; 25 | import java.util.Collection; 26 | import java.util.Comparator; 27 | import java.util.Optional; 28 | import java.util.Spliterator; 29 | import java.util.concurrent.ForkJoinPool; 30 | import java.util.concurrent.ForkJoinTask; 31 | import java.util.function.BiConsumer; 32 | import java.util.function.BiFunction; 33 | import java.util.function.BinaryOperator; 34 | import java.util.function.Consumer; 35 | import java.util.function.Function; 36 | import java.util.function.IntFunction; 37 | import java.util.function.Predicate; 38 | import java.util.function.Supplier; 39 | import java.util.function.ToDoubleFunction; 40 | import java.util.function.ToIntFunction; 41 | import java.util.function.ToLongFunction; 42 | import java.util.function.UnaryOperator; 43 | import java.util.stream.Collector; 44 | import java.util.stream.DoubleStream; 45 | import java.util.stream.IntStream; 46 | import java.util.stream.LongStream; 47 | import java.util.stream.Stream; 48 | import java.util.stream.StreamSupport; 49 | import static java.util.Arrays.stream; 50 | import static java.util.Objects.requireNonNull; 51 | import static java.util.stream.StreamSupport.stream; 52 | 53 | /** 54 | * An implementation of {@link Stream} which uses a custom {@link ForkJoinPool} for parallel aggregate operations. 55 | *

56 | * The following example illustrates an aggregate operation using {@link ParallelStreamSupport} with a custom 57 | * {@link ForkJoinPool}: 58 | *

 59 |  * ForkJoinPool pool = new ForkJoinPool();
 60 |  * int sum = ParallelStreamSupport.parallelStream(widgets, pool)
 61 |  *     .filter(w -> w.getColor() == RED)
 62 |  *     .mapToInt(w -> w.getWeight())
 63 |  *     .sum();
 64 |  * 
65 | *

66 | * In case this stream is configured for parallel execution, i.e. {@link #isParallel()} returns {@code true}, a 67 | * terminal 68 | * operation will be executed as {@link ForkJoinTask} in the custom {@link ForkJoinPool}. Otherwise it will be 69 | * executed in the calling thread. 70 | *

71 | * This implementation offers various factory methods which are based on: 72 | *
    73 | *
  • The static factory methods of {@link Stream}, which are meaningful for parallel streams
  • 74 | *
  • {@link Collection#parallelStream()}
  • 75 | *
  • {@link Arrays#stream(Object[])}
  • 76 | *
  • {@link StreamSupport#stream(Spliterator, boolean)}
  • 77 | *
  • {@link StreamSupport#stream(Supplier, int, boolean)}
  • 78 | *
79 | * 80 | * @param The type of the stream elements. 81 | * @apiNote

82 | * Internally, this stream wraps a stream which is initially created in one of the static factory methods. Whenever a 83 | * non-terminal operation is called the underlying stream will be replaced with the result of calling the same method 84 | * on that stream. The return value of these operations is always this stream or, in case of operations that return a 85 | * different type of stream, one of {@link ParallelIntStreamSupport}, {@link ParallelLongStreamSupport} or 86 | * {@link ParallelDoubleStreamSupport}. 87 | *

88 | *

89 | * Although each factory method returns a parallel stream, calling {@link #sequential()} is still possible and leads to 90 | * sequential execution of a terminal operation within the calling thread. 91 | *

92 | * @implNote

93 | * See the class documentation for {@link Stream} and the package documentation for 94 | * java.util.stream for 95 | * additional specification. 96 | *

97 | */ 98 | public class ParallelStreamSupport extends AbstractParallelStreamSupport> implements Stream { 99 | 100 | /** 101 | * Constructor for internal use within this package only. 102 | * 103 | * @param delegate Stream to delegate each operation. 104 | * @param workerPool Worker pool for executing terminal operations in parallel. Must not be {@code null}. 105 | */ 106 | ParallelStreamSupport(Stream delegate, ForkJoinPool workerPool) { 107 | super(delegate, workerPool); 108 | } 109 | 110 | /** 111 | * Creates a parallel stream from the given Collection. This operation is similar to 112 | * {@link Collection#parallelStream()} with the difference that a parallel 113 | * terminal 114 | * operation will be executed in the given {@link ForkJoinPool}. 115 | * 116 | * @param The type of stream elements. 117 | * @param collection Collection to create the parallel stream from. Must not be {@code null}. 118 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 119 | * @return A parallel stream that executes a terminal operation in the given {@link ForkJoinPool}. 120 | * @see Collection#parallelStream() 121 | */ 122 | public static Stream parallelStream(Collection collection, ForkJoinPool workerPool) { 123 | requireNonNull(collection, "Collection must not be null"); 124 | 125 | return new ParallelStreamSupport<>(collection.parallelStream(), workerPool); 126 | } 127 | 128 | /** 129 | * Creates a parallel stream from the given Array. This operation is similar to calling 130 | * {@code Arrays.stream(array).parallel()} with the difference that a parallel 131 | * terminal 132 | * operation will be executed in the given {@link ForkJoinPool}. 133 | * 134 | * @param The type of stream elements. 135 | * @param array Array to create the parallel stream from. Must not be {@code null}. 136 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 137 | * @return A parallel stream that executes a terminal operation in the given {@link ForkJoinPool}. 138 | * @see Arrays#stream(Object[]) 139 | */ 140 | public static Stream parallelStream(T[] array, ForkJoinPool workerPool) { 141 | requireNonNull(array, "Array must not be null"); 142 | 143 | return new ParallelStreamSupport<>(stream(array).parallel(), workerPool); 144 | } 145 | 146 | /** 147 | * Creates a parallel stream from the given Spliterator. This operation is similar to calling 148 | * {@code StreamSupport.stream(spliterator, true)} with the difference that a parallel 149 | * terminal 150 | * operation will be executed in the given {@link ForkJoinPool}. 151 | * 152 | * @param The type of stream elements. 153 | * @param spliterator A {@code Spliterator} describing the stream elements. Must not be {@code null}. 154 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 155 | * @return A parallel stream that executes a terminal operation in the given {@link ForkJoinPool}. 156 | * @see StreamSupport#stream(Spliterator, boolean) 157 | */ 158 | public static Stream parallelStream(Spliterator spliterator, ForkJoinPool workerPool) { 159 | requireNonNull(spliterator, "Spliterator must not be null"); 160 | 161 | return new ParallelStreamSupport<>(stream(spliterator, true), workerPool); 162 | } 163 | 164 | /** 165 | * Creates a parallel stream from the given Spliterator supplier. This operation is similar to 166 | * calling {@code StreamSupport.stream(supplier, characteristics, true)} with the difference that a parallel 167 | * terminal 168 | * operation will be executed in the given {@link ForkJoinPool}. 169 | * 170 | * @param The type of stream elements. 171 | * @param supplier A {@code Supplier} of a {@code Spliterator}. Must not be {@code null}. 172 | * @param characteristics Spliterator characteristics of the supplied {@code Spliterator}. The characteristics must 173 | * be equal to {@code supplier.get().characteristics()}, otherwise undefined behavior may occur when terminal 174 | * operation commences. 175 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 176 | * @return A parallel stream that executes a terminal operation in the given {@link ForkJoinPool}. 177 | * @see StreamSupport#stream(Supplier, int, boolean) 178 | */ 179 | public static Stream parallelStream(Supplier> supplier, int characteristics, ForkJoinPool workerPool) { 180 | requireNonNull(supplier, "Supplier must not be null"); 181 | 182 | return new ParallelStreamSupport<>(stream(supplier, characteristics, true), workerPool); 183 | } 184 | 185 | /** 186 | * Creates a parallel stream from the given {@link Builder}. This operation is similar to calling 187 | * {@code builder.build().parallel()} with the difference that a parallel 188 | * terminal 189 | * operation will be executed in the given {@link ForkJoinPool}. 190 | * 191 | * @param The type of stream elements. 192 | * @param builder The builder to create the stream from. Must not be {@code null}. 193 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 194 | * @return A parallel stream that executes a terminal operation in the given {@link ForkJoinPool}. 195 | * @see Stream#builder() 196 | */ 197 | public static Stream parallelStream(Builder builder, ForkJoinPool workerPool) { 198 | requireNonNull(builder, "Builder must not be null"); 199 | 200 | return new ParallelStreamSupport<>(builder.build().parallel(), workerPool); 201 | } 202 | 203 | /** 204 | * Creates a parallel infinite ordered stream produced by iterative application of a function 205 | * {@code f} to an initial element {@code seed}. This operation is similar to calling {@code Stream.iterate(seed, 206 | * operator).parallel()} with the difference that a parallel 207 | * terminal 208 | * operation will be executed in the given {@link ForkJoinPool}. 209 | * 210 | * @param The type of stream elements. 211 | * @param seed The initial element. 212 | * @param operator A function to be applied to to the previous element to produce a new element. Must not be {@code null}. 213 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 214 | * @return A parallel stream that executes a terminal operation in the given {@link ForkJoinPool}. 215 | * @see Stream#iterate(Object, UnaryOperator) 216 | */ 217 | public static Stream iterate(T seed, UnaryOperator operator, ForkJoinPool workerPool) { 218 | requireNonNull(operator, "Operator must not be null"); 219 | 220 | return new ParallelStreamSupport<>(Stream.iterate(seed, operator).parallel(), workerPool); 221 | } 222 | 223 | /** 224 | * Creates a parallel infinite sequential unordered stream where each element is generated by the 225 | * provided {@code Supplier}. This operation is similar to calling {@code Stream.generate(supplier).parallel()} with 226 | * the difference that a parallel 227 | * terminal 228 | * operation will be executed in the given {@link ForkJoinPool}. 229 | * 230 | * @param The type of stream elements. 231 | * @param supplier The {@code Supplier} of generated elements. Must not be {@code null}. 232 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 233 | * @return A parallel stream that executes a terminal operation in the given {@link ForkJoinPool}. 234 | * @see Stream#generate(Supplier) 235 | */ 236 | public static Stream generate(Supplier supplier, ForkJoinPool workerPool) { 237 | requireNonNull(supplier, "Supplier must not be null"); 238 | 239 | return new ParallelStreamSupport<>(Stream.generate(supplier).parallel(), workerPool); 240 | } 241 | 242 | /** 243 | * Creates a lazily concatenated parallel stream whose elements are all the elements of the first 244 | * stream followed by all the elements of the second stream. This operation is similar to calling 245 | * {@code Stream.concat(a, b).parallel()} with the difference that a parallel 246 | * terminal 247 | * operation will be executed in the given {@link ForkJoinPool}. 248 | * 249 | * @param The type of stream elements. 250 | * @param a The first stream. Must not be {@code null}. 251 | * @param b The second stream. Must not be {@code null}. 252 | * @param workerPool Thread pool for parallel execution of a terminal operation. Must not be {@code null}. 253 | * @return A parallel stream that executes a terminal operation in the given {@link ForkJoinPool}. 254 | * @see Stream#concat(Stream, Stream) 255 | */ 256 | public static Stream concat(Stream a, Stream b, ForkJoinPool workerPool) { 257 | requireNonNull(a, "Stream a must not be null"); 258 | requireNonNull(b, "Stream b must not be null"); 259 | 260 | return new ParallelStreamSupport<>(Stream.concat(a, b).parallel(), workerPool); 261 | } 262 | 263 | @Override 264 | public Stream filter(Predicate predicate) { 265 | this.delegate = this.delegate.filter(predicate); 266 | return this; 267 | } 268 | 269 | @Override 270 | public Stream map(Function mapper) { 271 | return new ParallelStreamSupport<>(this.delegate.map(mapper), this.workerPool); 272 | } 273 | 274 | @Override 275 | public IntStream mapToInt(ToIntFunction mapper) { 276 | return new ParallelIntStreamSupport(this.delegate.mapToInt(mapper), this.workerPool); 277 | } 278 | 279 | @Override 280 | public LongStream mapToLong(ToLongFunction mapper) { 281 | return new ParallelLongStreamSupport(this.delegate.mapToLong(mapper), this.workerPool); 282 | } 283 | 284 | @Override 285 | public DoubleStream mapToDouble(ToDoubleFunction mapper) { 286 | return new ParallelDoubleStreamSupport(this.delegate.mapToDouble(mapper), this.workerPool); 287 | } 288 | 289 | @Override 290 | public Stream flatMap(Function> mapper) { 291 | return new ParallelStreamSupport<>(this.delegate.flatMap(mapper), this.workerPool); 292 | } 293 | 294 | @Override 295 | public IntStream flatMapToInt(Function mapper) { 296 | return new ParallelIntStreamSupport(this.delegate.flatMapToInt(mapper), this.workerPool); 297 | } 298 | 299 | @Override 300 | public LongStream flatMapToLong(Function mapper) { 301 | return new ParallelLongStreamSupport(this.delegate.flatMapToLong(mapper), this.workerPool); 302 | } 303 | 304 | @Override 305 | public DoubleStream flatMapToDouble(Function mapper) { 306 | return new ParallelDoubleStreamSupport(this.delegate.flatMapToDouble(mapper), this.workerPool); 307 | } 308 | 309 | @Override 310 | public Stream distinct() { 311 | this.delegate = this.delegate.distinct(); 312 | return this; 313 | } 314 | 315 | @Override 316 | public Stream sorted() { 317 | this.delegate = this.delegate.sorted(); 318 | return this; 319 | } 320 | 321 | @Override 322 | public Stream sorted(Comparator comparator) { 323 | this.delegate = this.delegate.sorted(comparator); 324 | return this; 325 | } 326 | 327 | @Override 328 | public Stream peek(Consumer action) { 329 | this.delegate = this.delegate.peek(action); 330 | return this; 331 | } 332 | 333 | @Override 334 | public Stream limit(long maxSize) { 335 | this.delegate = this.delegate.limit(maxSize); 336 | return this; 337 | } 338 | 339 | @Override 340 | public Stream skip(long n) { 341 | this.delegate = this.delegate.skip(n); 342 | return this; 343 | } 344 | 345 | @Override 346 | public Stream takeWhile(Predicate predicate) { 347 | this.delegate = this.delegate.takeWhile(predicate); 348 | return this; 349 | } 350 | 351 | @Override 352 | public Stream dropWhile(Predicate predicate) { 353 | this.delegate = this.delegate.dropWhile(predicate); 354 | return this; 355 | } 356 | 357 | // Terminal operations 358 | 359 | @Override 360 | public void forEach(Consumer action) { 361 | execute(() -> this.delegate.forEach(action)); 362 | } 363 | 364 | @Override 365 | public void forEachOrdered(Consumer action) { 366 | execute(() -> this.delegate.forEachOrdered(action)); 367 | } 368 | 369 | @Override 370 | public Object[] toArray() { 371 | return execute(() -> this.delegate.toArray()); 372 | } 373 | 374 | @Override 375 | public A[] toArray(IntFunction generator) { 376 | return execute(() -> this.delegate.toArray(generator)); 377 | } 378 | 379 | @Override 380 | public T reduce(T identity, BinaryOperator accumulator) { 381 | return execute(() -> this.delegate.reduce(identity, accumulator)); 382 | } 383 | 384 | @Override 385 | public Optional reduce(BinaryOperator accumulator) { 386 | return execute(() -> this.delegate.reduce(accumulator)); 387 | } 388 | 389 | @Override 390 | public U reduce(U identity, BiFunction accumulator, BinaryOperator combiner) { 391 | return execute(() -> this.delegate.reduce(identity, accumulator, combiner)); 392 | } 393 | 394 | @Override 395 | public R collect(Supplier supplier, BiConsumer accumulator, BiConsumer combiner) { 396 | return execute(() -> this.delegate.collect(supplier, accumulator, combiner)); 397 | } 398 | 399 | @Override 400 | public R collect(Collector collector) { 401 | return execute(() -> this.delegate.collect(collector)); 402 | } 403 | 404 | @Override 405 | public Optional min(Comparator comparator) { 406 | return execute(() -> this.delegate.min(comparator)); 407 | } 408 | 409 | @Override 410 | public Optional max(Comparator comparator) { 411 | return execute(() -> this.delegate.max(comparator)); 412 | } 413 | 414 | @Override 415 | public long count() { 416 | return execute(() -> this.delegate.count()); 417 | } 418 | 419 | @Override 420 | public boolean anyMatch(Predicate predicate) { 421 | return execute(() -> this.delegate.anyMatch(predicate)); 422 | } 423 | 424 | @Override 425 | public boolean allMatch(Predicate predicate) { 426 | return execute(() -> this.delegate.allMatch(predicate)); 427 | } 428 | 429 | @Override 430 | public boolean noneMatch(Predicate predicate) { 431 | return execute(() -> this.delegate.noneMatch(predicate)); 432 | } 433 | 434 | @Override 435 | public Optional findFirst() { 436 | return execute(() -> this.delegate.findFirst()); 437 | } 438 | 439 | @Override 440 | public Optional findAny() { 441 | return execute(() -> this.delegate.findAny()); 442 | } 443 | } 444 | -------------------------------------------------------------------------------- /src/test/java/com/github/ferstl/streams/AbstractParallelStreamSupportTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Stefan Ferstl 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.github.ferstl.streams; 23 | 24 | import java.util.Iterator; 25 | import java.util.Spliterator; 26 | import java.util.concurrent.Callable; 27 | import java.util.concurrent.ForkJoinPool; 28 | import java.util.concurrent.TimeUnit; 29 | import java.util.concurrent.atomic.AtomicBoolean; 30 | import java.util.stream.BaseStream; 31 | import org.junit.jupiter.api.AfterEach; 32 | import org.junit.jupiter.api.BeforeEach; 33 | import org.junit.jupiter.api.Test; 34 | import static org.junit.jupiter.api.Assertions.assertEquals; 35 | import static org.junit.jupiter.api.Assertions.assertSame; 36 | import static org.junit.jupiter.api.Assertions.assertThrows; 37 | import static org.junit.jupiter.api.Assertions.assertTrue; 38 | import static org.junit.jupiter.api.Assertions.fail; 39 | import static org.mockito.Mockito.mock; 40 | import static org.mockito.Mockito.verify; 41 | import static org.mockito.Mockito.when; 42 | 43 | @SuppressWarnings("ResultOfMethodCallIgnored") 44 | public abstract class AbstractParallelStreamSupportTest, R extends AbstractParallelStreamSupport> { 45 | 46 | ForkJoinPool workerPool; 47 | S delegateMock; 48 | R parallelStreamSupportMock; 49 | 50 | protected abstract R createParallelStreamSupportMock(ForkJoinPool workerPool); 51 | 52 | @BeforeEach 53 | void before() { 54 | this.workerPool = new ForkJoinPool(1); 55 | this.parallelStreamSupportMock = createParallelStreamSupportMock(this.workerPool); 56 | this.delegateMock = this.parallelStreamSupportMock.delegate; 57 | } 58 | 59 | @AfterEach 60 | void after() throws InterruptedException { 61 | this.workerPool.shutdown(); 62 | this.workerPool.awaitTermination(1, TimeUnit.SECONDS); 63 | } 64 | 65 | @Test 66 | @SuppressWarnings({"unchecked", "rawtypes"}) 67 | void iterator() { 68 | Iterator iteratorMock = mock(Iterator.class); 69 | when(this.delegateMock.iterator()).thenReturn((Iterator) iteratorMock); 70 | Iterator iterator = this.parallelStreamSupportMock.iterator(); 71 | 72 | verify(this.delegateMock).iterator(); 73 | assertSame(iteratorMock, iterator); 74 | } 75 | 76 | @Test 77 | @SuppressWarnings({"unchecked", "rawtypes"}) 78 | void spliterator() { 79 | Spliterator spliteratorMock = mock(Spliterator.class); 80 | when(this.delegateMock.spliterator()).thenReturn((Spliterator) spliteratorMock); 81 | Spliterator spliterator = this.parallelStreamSupportMock.spliterator(); 82 | 83 | verify(this.delegateMock).spliterator(); 84 | assertSame(spliteratorMock, spliterator); 85 | } 86 | 87 | @Test 88 | void isParallel() { 89 | when(this.delegateMock.isParallel()).thenReturn(true); 90 | boolean parallel = this.parallelStreamSupportMock.isParallel(); 91 | 92 | verify(this.delegateMock).isParallel(); 93 | assertTrue(parallel); 94 | } 95 | 96 | @Test 97 | void sequential() { 98 | BaseStream stream = this.parallelStreamSupportMock.sequential(); 99 | 100 | verify(this.delegateMock).sequential(); 101 | assertSame(this.parallelStreamSupportMock, stream); 102 | } 103 | 104 | @Test 105 | void parallel() { 106 | BaseStream stream = this.parallelStreamSupportMock.parallel(); 107 | 108 | verify(this.delegateMock).parallel(); 109 | assertSame(this.parallelStreamSupportMock, stream); 110 | } 111 | 112 | @Test 113 | void unordered() { 114 | BaseStream stream = this.parallelStreamSupportMock.unordered(); 115 | 116 | verify(this.delegateMock).unordered(); 117 | assertSame(this.parallelStreamSupportMock, stream); 118 | } 119 | 120 | @Test 121 | void onClose() { 122 | Runnable r = () -> { 123 | }; 124 | BaseStream stream = this.parallelStreamSupportMock.onClose(r); 125 | 126 | verify(this.delegateMock).onClose(r); 127 | assertSame(this.parallelStreamSupportMock, stream); 128 | } 129 | 130 | @Test 131 | void close() { 132 | this.parallelStreamSupportMock.close(); 133 | 134 | verify(this.delegateMock).close(); 135 | } 136 | 137 | @Test 138 | void executeWithRunnable() { 139 | AtomicBoolean b = new AtomicBoolean(false); 140 | 141 | this.parallelStreamSupportMock.execute(() -> b.set(true)); 142 | 143 | assertTrue(b.get()); 144 | } 145 | 146 | @Test 147 | void executeWithRunnableThrowingException() { 148 | Runnable r = () -> { 149 | throw new RuntimeException("boom"); 150 | }; 151 | 152 | assertThrows(RuntimeException.class, () -> this.parallelStreamSupportMock.execute(r)); 153 | } 154 | 155 | @Test 156 | void executeWithCallable() { 157 | AtomicBoolean b = new AtomicBoolean(false); 158 | Callable c = () -> { 159 | b.set(true); 160 | return null; 161 | }; 162 | 163 | this.parallelStreamSupportMock.execute(c); 164 | 165 | assertTrue(b.get()); 166 | } 167 | 168 | @Test 169 | void executeWithCallableThrowingError() { 170 | Callable c = () -> { 171 | throw new AssertionError("boom"); 172 | }; 173 | 174 | assertThrows(AssertionError.class, () -> this.parallelStreamSupportMock.execute(c)); 175 | } 176 | 177 | @Test 178 | void executeWithCallableThrowingCheckedException() { 179 | Exception e = new Exception("boom"); 180 | try { 181 | Callable c = () -> { 182 | throw e; 183 | }; 184 | 185 | this.parallelStreamSupportMock.execute(c); 186 | fail("Expect runtime exception."); 187 | } catch (RuntimeException rte) { 188 | assertEquals(e, rte.getCause()); 189 | } 190 | } 191 | } 192 | -------------------------------------------------------------------------------- /src/test/java/com/github/ferstl/streams/ParallelDoubleStreamSupportTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Stefan Ferstl 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.github.ferstl.streams; 23 | 24 | import java.util.ArrayList; 25 | import java.util.DoubleSummaryStatistics; 26 | import java.util.OptionalDouble; 27 | import java.util.PrimitiveIterator; 28 | import java.util.Spliterator; 29 | import java.util.concurrent.ForkJoinPool; 30 | import java.util.concurrent.ForkJoinWorkerThread; 31 | import java.util.concurrent.atomic.AtomicReference; 32 | import java.util.function.BiConsumer; 33 | import java.util.function.DoubleBinaryOperator; 34 | import java.util.function.DoubleConsumer; 35 | import java.util.function.DoubleFunction; 36 | import java.util.function.DoublePredicate; 37 | import java.util.function.DoubleSupplier; 38 | import java.util.function.DoubleToIntFunction; 39 | import java.util.function.DoubleToLongFunction; 40 | import java.util.function.DoubleUnaryOperator; 41 | import java.util.function.ObjDoubleConsumer; 42 | import java.util.function.Supplier; 43 | import java.util.stream.DoubleStream; 44 | import java.util.stream.DoubleStream.Builder; 45 | import java.util.stream.IntStream; 46 | import java.util.stream.LongStream; 47 | import java.util.stream.Stream; 48 | import org.junit.jupiter.api.BeforeEach; 49 | import org.junit.jupiter.api.Test; 50 | import static java.lang.Thread.currentThread; 51 | import static org.hamcrest.MatcherAssert.assertThat; 52 | import static org.hamcrest.Matchers.instanceOf; 53 | import static org.junit.jupiter.api.Assertions.assertArrayEquals; 54 | import static org.junit.jupiter.api.Assertions.assertEquals; 55 | import static org.junit.jupiter.api.Assertions.assertFalse; 56 | import static org.junit.jupiter.api.Assertions.assertSame; 57 | import static org.junit.jupiter.api.Assertions.assertThrows; 58 | import static org.junit.jupiter.api.Assertions.assertTrue; 59 | import static org.mockito.ArgumentMatchers.any; 60 | import static org.mockito.ArgumentMatchers.anyDouble; 61 | import static org.mockito.Mockito.mock; 62 | import static org.mockito.Mockito.verify; 63 | import static org.mockito.Mockito.when; 64 | 65 | 66 | @SuppressWarnings("ResultOfMethodCallIgnored") 67 | public class ParallelDoubleStreamSupportTest extends AbstractParallelStreamSupportTest { 68 | 69 | private Stream mappedDelegateMock; 70 | private IntStream mappedIntDelegateMock; 71 | private LongStream mappedLongDelegateMock; 72 | private DoubleStream mappedDoubleDelegateMock; 73 | private PrimitiveIterator.OfDouble iteratorMock; 74 | private Spliterator.OfDouble spliteratorMock; 75 | private double[] toArrayResult; 76 | private DoubleSummaryStatistics summaryStatistics; 77 | 78 | private ParallelDoubleStreamSupport parallelDoubleStreamSupport; 79 | 80 | @Override 81 | protected ParallelDoubleStreamSupport createParallelStreamSupportMock(ForkJoinPool workerPool) { 82 | return new ParallelDoubleStreamSupport(mock(DoubleStream.class), workerPool); 83 | } 84 | 85 | @BeforeEach 86 | @SuppressWarnings({"unchecked", "rawtypes"}) 87 | void init() { 88 | // Precondition for all tests 89 | assertFalse(currentThread() instanceof ForkJoinWorkerThread, "This test must not run in a ForkJoinPool"); 90 | 91 | this.mappedDelegateMock = mock(Stream.class); 92 | this.mappedIntDelegateMock = mock(IntStream.class); 93 | this.mappedLongDelegateMock = mock(LongStream.class); 94 | this.mappedDoubleDelegateMock = mock(DoubleStream.class); 95 | this.iteratorMock = mock(PrimitiveIterator.OfDouble.class); 96 | this.spliteratorMock = mock(Spliterator.OfDouble.class); 97 | this.toArrayResult = new double[0]; 98 | this.summaryStatistics = new DoubleSummaryStatistics(); 99 | 100 | when(this.delegateMock.map(any())).thenReturn(this.mappedDoubleDelegateMock); 101 | when(this.delegateMock.mapToObj(any())).thenReturn((Stream) this.mappedDelegateMock); 102 | when(this.delegateMock.mapToInt(any())).thenReturn(this.mappedIntDelegateMock); 103 | when(this.delegateMock.mapToLong(any())).thenReturn(this.mappedLongDelegateMock); 104 | when(this.delegateMock.flatMap(any())).thenReturn(this.mappedDoubleDelegateMock); 105 | when(this.delegateMock.iterator()).thenReturn(this.iteratorMock); 106 | when(this.delegateMock.spliterator()).thenReturn(this.spliteratorMock); 107 | when(this.delegateMock.isParallel()).thenReturn(false); 108 | when(this.delegateMock.toArray()).thenReturn(this.toArrayResult); 109 | when(this.delegateMock.reduce(anyDouble(), any())).thenReturn(42.0); 110 | when(this.delegateMock.reduce(any())).thenReturn(OptionalDouble.of(42.0)); 111 | when(this.delegateMock.collect(any(), any(), any())).thenReturn("collect"); 112 | when(this.delegateMock.sum()).thenReturn(42.0); 113 | when(this.delegateMock.min()).thenReturn(OptionalDouble.of(42.0)); 114 | when(this.delegateMock.max()).thenReturn(OptionalDouble.of(42.0)); 115 | when(this.delegateMock.count()).thenReturn(42L); 116 | when(this.delegateMock.average()).thenReturn(OptionalDouble.of(42.0)); 117 | when(this.delegateMock.summaryStatistics()).thenReturn(this.summaryStatistics); 118 | when(this.delegateMock.anyMatch(any())).thenReturn(true); 119 | when(this.delegateMock.allMatch(any())).thenReturn(true); 120 | when(this.delegateMock.noneMatch(any())).thenReturn(true); 121 | when(this.delegateMock.findFirst()).thenReturn(OptionalDouble.of(42.0)); 122 | when(this.delegateMock.findAny()).thenReturn(OptionalDouble.of(42.0)); 123 | when(this.delegateMock.boxed()).thenReturn((Stream) this.mappedDelegateMock); 124 | 125 | DoubleStream delegate = DoubleStream.of(1.0).parallel(); 126 | this.parallelDoubleStreamSupport = new ParallelDoubleStreamSupport(delegate, this.workerPool); 127 | } 128 | 129 | 130 | @Test 131 | void parallelStreamWithArray() { 132 | DoubleStream stream = ParallelDoubleStreamSupport.parallelStream(new double[]{42.0}, this.workerPool); 133 | 134 | assertThat(stream, instanceOf(ParallelDoubleStreamSupport.class)); 135 | assertTrue(stream.isParallel()); 136 | assertEquals(OptionalDouble.of(42.0), stream.findAny()); 137 | } 138 | 139 | @Test 140 | void parallelStreamWithNullArray() { 141 | assertThrows(NullPointerException.class, () -> ParallelDoubleStreamSupport.parallelStream((double[]) null, this.workerPool)); 142 | } 143 | 144 | @Test 145 | void parallelStreamSupportWithSpliterator() { 146 | Spliterator.OfDouble spliterator = DoubleStream.of(42.0).spliterator(); 147 | DoubleStream stream = ParallelDoubleStreamSupport.parallelStream(spliterator, this.workerPool); 148 | 149 | assertThat(stream, instanceOf(ParallelDoubleStreamSupport.class)); 150 | assertTrue(stream.isParallel()); 151 | assertEquals(OptionalDouble.of(42.0), stream.findAny()); 152 | } 153 | 154 | @Test 155 | void parallelStreamSupportWithNullSpliterator() { 156 | assertThrows(NullPointerException.class, () -> ParallelDoubleStreamSupport.parallelStream((Spliterator.OfDouble) null, this.workerPool)); 157 | } 158 | 159 | @Test 160 | void parallelStreamSupportWithSpliteratorSupplier() { 161 | Supplier supplier = () -> DoubleStream.of(42.0).spliterator(); 162 | DoubleStream stream = ParallelDoubleStreamSupport.parallelStream(supplier, 0, this.workerPool); 163 | 164 | assertThat(stream, instanceOf(ParallelDoubleStreamSupport.class)); 165 | assertTrue(stream.isParallel()); 166 | assertEquals(OptionalDouble.of(42.0), stream.findAny()); 167 | } 168 | 169 | @Test 170 | void parallelStreamSupportWithNullSpliteratorSupplier() { 171 | assertThrows(NullPointerException.class, () -> ParallelDoubleStreamSupport.parallelStream(null, 0, this.workerPool)); 172 | } 173 | 174 | @Test 175 | void parallelStreamWithBuilder() { 176 | Builder builder = DoubleStream.builder(); 177 | builder.accept(42.0); 178 | DoubleStream stream = ParallelDoubleStreamSupport.parallelStream(builder, this.workerPool); 179 | 180 | assertThat(stream, instanceOf(ParallelDoubleStreamSupport.class)); 181 | assertTrue(stream.isParallel()); 182 | assertEquals(OptionalDouble.of(42.0), stream.findAny()); 183 | } 184 | 185 | @Test 186 | void parallelStreamWithNullBuilder() { 187 | assertThrows(NullPointerException.class, () -> ParallelDoubleStreamSupport.parallelStream((Builder) null, this.workerPool)); 188 | } 189 | 190 | @Test 191 | void iterate() { 192 | DoubleUnaryOperator operator = a -> a; 193 | DoubleStream stream = ParallelDoubleStreamSupport.iterate(42.0, operator, this.workerPool); 194 | 195 | assertThat(stream, instanceOf(ParallelDoubleStreamSupport.class)); 196 | assertTrue(stream.isParallel()); 197 | assertEquals(OptionalDouble.of(42.0), stream.findAny()); 198 | } 199 | 200 | @Test 201 | void iterateWithNullOperator() { 202 | assertThrows(NullPointerException.class, () -> ParallelDoubleStreamSupport.iterate(42.0, null, this.workerPool)); 203 | } 204 | 205 | @Test 206 | void generate() { 207 | DoubleSupplier supplier = () -> 42.0; 208 | DoubleStream stream = ParallelDoubleStreamSupport.generate(supplier, this.workerPool); 209 | 210 | assertThat(stream, instanceOf(ParallelDoubleStreamSupport.class)); 211 | assertTrue(stream.isParallel()); 212 | assertEquals(OptionalDouble.of(42.0), stream.findAny()); 213 | } 214 | 215 | @Test 216 | void generateWithNullSupplier() { 217 | assertThrows(NullPointerException.class, () -> ParallelDoubleStreamSupport.generate(null, this.workerPool)); 218 | } 219 | 220 | @Test 221 | void concat() { 222 | DoubleStream a = DoubleStream.of(42.0); 223 | DoubleStream b = DoubleStream.of(43); 224 | DoubleStream stream = ParallelDoubleStreamSupport.concat(a, b, this.workerPool); 225 | 226 | assertThat(stream, instanceOf(ParallelDoubleStreamSupport.class)); 227 | assertTrue(stream.isParallel()); 228 | assertArrayEquals(stream.toArray(), new double[]{42.0, 43.0}, 0.000001); 229 | } 230 | 231 | @Test 232 | void concatWithNullStreamA() { 233 | assertThrows(NullPointerException.class, () -> ParallelDoubleStreamSupport.concat(null, DoubleStream.of(42.0), this.workerPool)); 234 | } 235 | 236 | @Test 237 | void concatWithNullStreamB() { 238 | assertThrows(NullPointerException.class, () -> ParallelDoubleStreamSupport.concat(DoubleStream.of(42.0), null, this.workerPool)); 239 | } 240 | 241 | @Test 242 | void filter() { 243 | DoublePredicate p = d -> true; 244 | DoubleStream stream = this.parallelStreamSupportMock.filter(p); 245 | 246 | verify(this.delegateMock).filter(p); 247 | assertSame(this.parallelStreamSupportMock, stream); 248 | } 249 | 250 | @Test 251 | void map() { 252 | DoubleUnaryOperator f = d -> 42; 253 | DoubleStream stream = this.parallelStreamSupportMock.map(f); 254 | 255 | verify(this.delegateMock).map(f); 256 | assertThat(stream, instanceOf(ParallelDoubleStreamSupport.class)); 257 | assertSame(((ParallelDoubleStreamSupport) stream).delegate, this.mappedDoubleDelegateMock); 258 | assertSame(((ParallelDoubleStreamSupport) stream).workerPool, this.workerPool); 259 | } 260 | 261 | @Test 262 | void mapToObj() { 263 | DoubleFunction f = d -> "x"; 264 | Stream stream = this.parallelStreamSupportMock.mapToObj(f); 265 | 266 | verify(this.delegateMock).mapToObj(f); 267 | assertThat(stream, instanceOf(ParallelStreamSupport.class)); 268 | assertSame(((ParallelStreamSupport) stream).delegate, this.mappedDelegateMock); 269 | assertSame(((ParallelStreamSupport) stream).workerPool, this.workerPool); 270 | } 271 | 272 | @Test 273 | void mapToInt() { 274 | DoubleToIntFunction f = d -> 1; 275 | IntStream stream = this.parallelStreamSupportMock.mapToInt(f); 276 | 277 | verify(this.delegateMock).mapToInt(f); 278 | assertThat(stream, instanceOf(ParallelIntStreamSupport.class)); 279 | assertSame(((ParallelIntStreamSupport) stream).delegate, this.mappedIntDelegateMock); 280 | assertSame(((ParallelIntStreamSupport) stream).workerPool, this.workerPool); 281 | } 282 | 283 | @Test 284 | void mapToLong() { 285 | DoubleToLongFunction f = d -> 1L; 286 | LongStream stream = this.parallelStreamSupportMock.mapToLong(f); 287 | 288 | verify(this.delegateMock).mapToLong(f); 289 | assertThat(stream, instanceOf(ParallelLongStreamSupport.class)); 290 | assertSame(((ParallelLongStreamSupport) stream).delegate, this.mappedLongDelegateMock); 291 | assertSame(((ParallelLongStreamSupport) stream).workerPool, this.workerPool); 292 | } 293 | 294 | @Test 295 | void flatMap() { 296 | DoubleFunction f = d -> DoubleStream.of(1.0); 297 | DoubleStream stream = this.parallelStreamSupportMock.flatMap(f); 298 | 299 | verify(this.delegateMock).flatMap(f); 300 | assertThat(stream, instanceOf(ParallelDoubleStreamSupport.class)); 301 | assertSame(((ParallelDoubleStreamSupport) stream).delegate, this.mappedDoubleDelegateMock); 302 | } 303 | 304 | @Test 305 | void distinct() { 306 | DoubleStream stream = this.parallelStreamSupportMock.distinct(); 307 | 308 | verify(this.delegateMock).distinct(); 309 | assertSame(this.parallelStreamSupportMock, stream); 310 | } 311 | 312 | @Test 313 | void sorted() { 314 | DoubleStream stream = this.parallelStreamSupportMock.sorted(); 315 | 316 | verify(this.delegateMock).sorted(); 317 | assertSame(this.parallelStreamSupportMock, stream); 318 | } 319 | 320 | @Test 321 | void peek() { 322 | DoubleConsumer c = d -> { 323 | }; 324 | DoubleStream stream = this.parallelStreamSupportMock.peek(c); 325 | 326 | verify(this.delegateMock).peek(c); 327 | assertSame(this.parallelStreamSupportMock, stream); 328 | } 329 | 330 | @Test 331 | void limit() { 332 | DoubleStream stream = this.parallelStreamSupportMock.limit(5); 333 | 334 | verify(this.delegateMock).limit(5); 335 | assertSame(this.parallelStreamSupportMock, stream); 336 | } 337 | 338 | @Test 339 | void skip() { 340 | DoubleStream stream = this.parallelStreamSupportMock.skip(5); 341 | 342 | verify(this.delegateMock).skip(5); 343 | assertSame(this.parallelStreamSupportMock, stream); 344 | } 345 | 346 | @Test 347 | void takeWhile() { 348 | DoublePredicate predicate = x -> true; 349 | DoubleStream stream = this.parallelStreamSupportMock.takeWhile(predicate); 350 | 351 | verify(this.delegateMock).takeWhile(predicate); 352 | assertSame(this.parallelStreamSupportMock, stream); 353 | } 354 | 355 | @Test 356 | void dropWhile() { 357 | DoublePredicate predicate = x -> true; 358 | DoubleStream stream = this.parallelStreamSupportMock.dropWhile(predicate); 359 | 360 | verify(this.delegateMock).dropWhile(predicate); 361 | assertSame(this.parallelStreamSupportMock, stream); 362 | } 363 | 364 | @Test 365 | void forEach() { 366 | DoubleConsumer c = d -> { 367 | }; 368 | this.parallelStreamSupportMock.forEach(c); 369 | 370 | verify(this.delegateMock).forEach(c); 371 | } 372 | 373 | @Test 374 | void forEachSequential() { 375 | this.parallelDoubleStreamSupport.sequential(); 376 | Thread thisThread = currentThread(); 377 | AtomicReference threadRef = new AtomicReference<>(); 378 | 379 | this.parallelDoubleStreamSupport.forEach(d -> threadRef.set(currentThread())); 380 | 381 | assertEquals(thisThread, threadRef.get()); 382 | } 383 | 384 | @Test 385 | void forEachParallel() { 386 | this.parallelDoubleStreamSupport.parallel(); 387 | AtomicReference threadRef = new AtomicReference<>(); 388 | 389 | this.parallelDoubleStreamSupport.forEach(d -> threadRef.set(currentThread())); 390 | 391 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 392 | } 393 | 394 | @Test 395 | void forEachOrdered() { 396 | DoubleConsumer c = d -> { 397 | }; 398 | this.parallelStreamSupportMock.forEachOrdered(c); 399 | 400 | verify(this.delegateMock).forEachOrdered(c); 401 | } 402 | 403 | @Test 404 | void forEachOrderedSequential() { 405 | this.parallelDoubleStreamSupport.sequential(); 406 | Thread thisThread = currentThread(); 407 | AtomicReference threadRef = new AtomicReference<>(); 408 | 409 | this.parallelDoubleStreamSupport.forEachOrdered(d -> threadRef.set(currentThread())); 410 | 411 | assertEquals(thisThread, threadRef.get()); 412 | } 413 | 414 | @Test 415 | void forEachOrderedParallel() { 416 | this.parallelDoubleStreamSupport.parallel(); 417 | AtomicReference threadRef = new AtomicReference<>(); 418 | 419 | this.parallelDoubleStreamSupport.forEachOrdered(d -> threadRef.set(currentThread())); 420 | 421 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 422 | } 423 | 424 | @Test 425 | void toArray() { 426 | double[] array = this.parallelStreamSupportMock.toArray(); 427 | 428 | verify(this.delegateMock).toArray(); 429 | assertSame(this.toArrayResult, array); 430 | } 431 | 432 | @Test 433 | void toArraySequential() { 434 | this.parallelDoubleStreamSupport.sequential(); 435 | Thread thisThread = currentThread(); 436 | AtomicReference threadRef = new AtomicReference<>(); 437 | 438 | this.parallelDoubleStreamSupport 439 | .peek(d -> threadRef.set(currentThread())) 440 | .toArray(); 441 | 442 | assertEquals(thisThread, threadRef.get()); 443 | } 444 | 445 | @Test 446 | void toArrayParallel() { 447 | this.parallelDoubleStreamSupport.parallel(); 448 | AtomicReference threadRef = new AtomicReference<>(); 449 | 450 | this.parallelDoubleStreamSupport 451 | .peek(d -> threadRef.set(currentThread())) 452 | .toArray(); 453 | 454 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 455 | } 456 | 457 | @Test 458 | void reduceWithIdentityAndAccumulator() { 459 | DoubleBinaryOperator accumulator = (a, b) -> b; 460 | double result = this.parallelStreamSupportMock.reduce(0, accumulator); 461 | 462 | verify(this.delegateMock).reduce(0, accumulator); 463 | assertEquals(42.0, result, 0.000001); 464 | } 465 | 466 | @Test 467 | void reduceWithIdentityAndAccumulatorSequential() { 468 | this.parallelDoubleStreamSupport.sequential(); 469 | DoubleBinaryOperator accumulator = (a, b) -> b; 470 | Thread thisThread = currentThread(); 471 | AtomicReference threadRef = new AtomicReference<>(); 472 | 473 | this.parallelDoubleStreamSupport 474 | .peek(d -> threadRef.set(currentThread())) 475 | .reduce(0, accumulator); 476 | 477 | assertEquals(thisThread, threadRef.get()); 478 | } 479 | 480 | @Test 481 | void reduceWithIdentityAndAccumulatorParallel() { 482 | this.parallelDoubleStreamSupport.parallel(); 483 | DoubleBinaryOperator accumulator = (a, b) -> b; 484 | AtomicReference threadRef = new AtomicReference<>(); 485 | 486 | this.parallelDoubleStreamSupport 487 | .peek(d -> threadRef.set(currentThread())) 488 | .reduce(0, accumulator); 489 | 490 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 491 | } 492 | 493 | @Test 494 | void reduceWithAccumulator() { 495 | DoubleBinaryOperator accumulator = (a, b) -> b; 496 | OptionalDouble result = this.parallelStreamSupportMock.reduce(accumulator); 497 | 498 | verify(this.delegateMock).reduce(accumulator); 499 | assertEquals(OptionalDouble.of(42), result); 500 | } 501 | 502 | @Test 503 | void reduceWithAccumulatorSequential() { 504 | this.parallelDoubleStreamSupport.sequential(); 505 | DoubleBinaryOperator accumulator = (a, b) -> b; 506 | Thread thisThread = currentThread(); 507 | AtomicReference threadRef = new AtomicReference<>(); 508 | 509 | this.parallelDoubleStreamSupport 510 | .peek(d -> threadRef.set(currentThread())) 511 | .reduce(accumulator); 512 | 513 | assertEquals(thisThread, threadRef.get()); 514 | } 515 | 516 | @Test 517 | void reduceWithAccumulatorParallel() { 518 | this.parallelDoubleStreamSupport.parallel(); 519 | DoubleBinaryOperator accumulator = (a, b) -> b; 520 | AtomicReference threadRef = new AtomicReference<>(); 521 | 522 | this.parallelDoubleStreamSupport 523 | .peek(d -> threadRef.set(currentThread())) 524 | .reduce(accumulator); 525 | 526 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 527 | } 528 | 529 | @Test 530 | void collectWithSupplierAndAccumulatorAndCombiner() { 531 | Supplier supplier = () -> "x"; 532 | ObjDoubleConsumer accumulator = (a, b) -> { 533 | }; 534 | BiConsumer combiner = (a, b) -> { 535 | }; 536 | 537 | String result = this.parallelStreamSupportMock.collect(supplier, accumulator, combiner); 538 | 539 | verify(this.delegateMock).collect(supplier, accumulator, combiner); 540 | assertEquals("collect", result); 541 | } 542 | 543 | @Test 544 | void collectWithSupplierAndAccumulatorAndCombinerSequential() { 545 | this.parallelDoubleStreamSupport.sequential(); 546 | Thread thisThread = currentThread(); 547 | AtomicReference threadRef = new AtomicReference<>(); 548 | 549 | this.parallelDoubleStreamSupport 550 | .peek(d -> threadRef.set(currentThread())) 551 | .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); 552 | 553 | assertEquals(thisThread, threadRef.get()); 554 | } 555 | 556 | @Test 557 | void collectWithSupplierAndAccumulatorAndCombinerParallel() { 558 | this.parallelDoubleStreamSupport.parallel(); 559 | AtomicReference threadRef = new AtomicReference<>(); 560 | 561 | this.parallelDoubleStreamSupport 562 | .peek(d -> threadRef.set(currentThread())) 563 | .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); 564 | 565 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 566 | } 567 | 568 | @Test 569 | void sum() { 570 | double result = this.parallelStreamSupportMock.sum(); 571 | 572 | verify(this.delegateMock).sum(); 573 | assertEquals(42.0, result, 0.000001); 574 | } 575 | 576 | @Test 577 | void sumSequential() { 578 | this.parallelDoubleStreamSupport.sequential(); 579 | Thread thisThread = currentThread(); 580 | AtomicReference threadRef = new AtomicReference<>(); 581 | 582 | this.parallelDoubleStreamSupport 583 | .peek(d -> threadRef.set(currentThread())) 584 | .sum(); 585 | 586 | assertEquals(thisThread, threadRef.get()); 587 | } 588 | 589 | @Test 590 | void sumParallel() { 591 | this.parallelDoubleStreamSupport.parallel(); 592 | AtomicReference threadRef = new AtomicReference<>(); 593 | 594 | this.parallelDoubleStreamSupport 595 | .peek(d -> threadRef.set(currentThread())) 596 | .sum(); 597 | 598 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 599 | } 600 | 601 | @Test 602 | void min() { 603 | OptionalDouble result = this.parallelStreamSupportMock.min(); 604 | 605 | verify(this.delegateMock).min(); 606 | assertEquals(OptionalDouble.of(42), result); 607 | } 608 | 609 | @Test 610 | void minSequential() { 611 | this.parallelDoubleStreamSupport.sequential(); 612 | Thread thisThread = currentThread(); 613 | AtomicReference threadRef = new AtomicReference<>(); 614 | 615 | this.parallelDoubleStreamSupport 616 | .peek(d -> threadRef.set(currentThread())) 617 | .min(); 618 | 619 | assertEquals(thisThread, threadRef.get()); 620 | } 621 | 622 | @Test 623 | void minParallel() { 624 | this.parallelDoubleStreamSupport.parallel(); 625 | AtomicReference threadRef = new AtomicReference<>(); 626 | 627 | this.parallelDoubleStreamSupport 628 | .peek(d -> threadRef.set(currentThread())) 629 | .min(); 630 | 631 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 632 | } 633 | 634 | @Test 635 | void max() { 636 | OptionalDouble result = this.parallelStreamSupportMock.max(); 637 | 638 | verify(this.delegateMock).max(); 639 | assertEquals(OptionalDouble.of(42), result); 640 | } 641 | 642 | @Test 643 | void maxSequential() { 644 | this.parallelDoubleStreamSupport.sequential(); 645 | Thread thisThread = currentThread(); 646 | AtomicReference threadRef = new AtomicReference<>(); 647 | 648 | this.parallelDoubleStreamSupport 649 | .peek(d -> threadRef.set(currentThread())) 650 | .max(); 651 | 652 | assertEquals(thisThread, threadRef.get()); 653 | } 654 | 655 | @Test 656 | void maxParallel() { 657 | this.parallelDoubleStreamSupport.parallel(); 658 | AtomicReference threadRef = new AtomicReference<>(); 659 | 660 | this.parallelDoubleStreamSupport 661 | .peek(d -> threadRef.set(currentThread())) 662 | .max(); 663 | 664 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 665 | } 666 | 667 | @Test 668 | void count() { 669 | long count = this.parallelStreamSupportMock.count(); 670 | 671 | verify(this.delegateMock).count(); 672 | assertEquals(42L, count); 673 | } 674 | 675 | @Test 676 | void countSequential() { 677 | this.parallelDoubleStreamSupport.sequential(); 678 | Thread thisThread = currentThread(); 679 | AtomicReference threadRef = new AtomicReference<>(); 680 | 681 | this.parallelDoubleStreamSupport 682 | .filter(d -> { 683 | // Don't use peek() in combination with count(). See Javadoc. 684 | threadRef.set(currentThread()); 685 | return true; 686 | }).count(); 687 | 688 | assertEquals(thisThread, threadRef.get()); 689 | } 690 | 691 | @Test 692 | void countParallel() { 693 | this.parallelDoubleStreamSupport.parallel(); 694 | AtomicReference threadRef = new AtomicReference<>(); 695 | 696 | this.parallelDoubleStreamSupport 697 | .filter(d -> { 698 | // Don't use peek() in combination with count(). See Javadoc. 699 | threadRef.set(currentThread()); 700 | return true; 701 | }).count(); 702 | 703 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 704 | } 705 | 706 | @Test 707 | void average() { 708 | OptionalDouble result = this.parallelStreamSupportMock.average(); 709 | 710 | verify(this.delegateMock).average(); 711 | assertEquals(OptionalDouble.of(42.0), result); 712 | } 713 | 714 | @Test 715 | void averageSequential() { 716 | this.parallelDoubleStreamSupport.sequential(); 717 | Thread thisThread = currentThread(); 718 | AtomicReference threadRef = new AtomicReference<>(); 719 | 720 | this.parallelDoubleStreamSupport 721 | .peek(d -> threadRef.set(currentThread())) 722 | .average(); 723 | 724 | assertEquals(thisThread, threadRef.get()); 725 | } 726 | 727 | @Test 728 | void averageParallel() { 729 | this.parallelDoubleStreamSupport.parallel(); 730 | AtomicReference threadRef = new AtomicReference<>(); 731 | 732 | this.parallelDoubleStreamSupport 733 | .peek(d -> threadRef.set(currentThread())) 734 | .average(); 735 | 736 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 737 | } 738 | 739 | @Test 740 | void summaryStatistics() { 741 | DoubleSummaryStatistics result = this.parallelStreamSupportMock.summaryStatistics(); 742 | 743 | verify(this.delegateMock).summaryStatistics(); 744 | assertEquals(this.summaryStatistics, result); 745 | } 746 | 747 | @Test 748 | void summaryStatisticsSequential() { 749 | this.parallelDoubleStreamSupport.sequential(); 750 | Thread thisThread = currentThread(); 751 | AtomicReference threadRef = new AtomicReference<>(); 752 | 753 | this.parallelDoubleStreamSupport 754 | .peek(d -> threadRef.set(currentThread())) 755 | .summaryStatistics(); 756 | 757 | assertEquals(thisThread, threadRef.get()); 758 | } 759 | 760 | @Test 761 | void summaryStatisticsParallel() { 762 | this.parallelDoubleStreamSupport.parallel(); 763 | AtomicReference threadRef = new AtomicReference<>(); 764 | 765 | this.parallelDoubleStreamSupport 766 | .peek(d -> threadRef.set(currentThread())) 767 | .summaryStatistics(); 768 | 769 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 770 | } 771 | 772 | @Test 773 | void anyMatch() { 774 | DoublePredicate p = d -> true; 775 | 776 | boolean result = this.parallelStreamSupportMock.anyMatch(p); 777 | 778 | verify(this.delegateMock).anyMatch(p); 779 | assertTrue(result); 780 | } 781 | 782 | @Test 783 | void anyMatchSequential() { 784 | this.parallelDoubleStreamSupport.sequential(); 785 | Thread thisThread = currentThread(); 786 | AtomicReference threadRef = new AtomicReference<>(); 787 | 788 | this.parallelDoubleStreamSupport 789 | .peek(d -> threadRef.set(currentThread())) 790 | .anyMatch(d -> true); 791 | 792 | assertEquals(thisThread, threadRef.get()); 793 | } 794 | 795 | @Test 796 | void anyMatchParallel() { 797 | this.parallelDoubleStreamSupport.parallel(); 798 | AtomicReference threadRef = new AtomicReference<>(); 799 | 800 | this.parallelDoubleStreamSupport 801 | .peek(d -> threadRef.set(currentThread())) 802 | .anyMatch(d -> true); 803 | 804 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 805 | } 806 | 807 | @Test 808 | void allMatch() { 809 | DoublePredicate p = d -> true; 810 | 811 | boolean result = this.parallelStreamSupportMock.allMatch(p); 812 | 813 | verify(this.delegateMock).allMatch(p); 814 | assertTrue(result); 815 | } 816 | 817 | @Test 818 | void allMatchSequential() { 819 | this.parallelDoubleStreamSupport.sequential(); 820 | Thread thisThread = currentThread(); 821 | AtomicReference threadRef = new AtomicReference<>(); 822 | 823 | this.parallelDoubleStreamSupport 824 | .peek(d -> threadRef.set(currentThread())) 825 | .allMatch(d -> true); 826 | 827 | assertEquals(thisThread, threadRef.get()); 828 | } 829 | 830 | @Test 831 | void allMatchParallel() { 832 | this.parallelDoubleStreamSupport.parallel(); 833 | AtomicReference threadRef = new AtomicReference<>(); 834 | 835 | this.parallelDoubleStreamSupport 836 | .peek(d -> threadRef.set(currentThread())) 837 | .allMatch(d -> true); 838 | 839 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 840 | } 841 | 842 | @Test 843 | void noneMatch() { 844 | DoublePredicate p = d -> true; 845 | 846 | boolean result = this.parallelStreamSupportMock.noneMatch(p); 847 | 848 | verify(this.delegateMock).noneMatch(p); 849 | assertTrue(result); 850 | } 851 | 852 | @Test 853 | void noneMatchSequential() { 854 | this.parallelDoubleStreamSupport.sequential(); 855 | Thread thisThread = currentThread(); 856 | AtomicReference threadRef = new AtomicReference<>(); 857 | 858 | this.parallelDoubleStreamSupport 859 | .peek(d -> threadRef.set(currentThread())) 860 | .noneMatch(d -> true); 861 | 862 | assertEquals(thisThread, threadRef.get()); 863 | } 864 | 865 | @Test 866 | void noneMatchParallel() { 867 | this.parallelDoubleStreamSupport.parallel(); 868 | AtomicReference threadRef = new AtomicReference<>(); 869 | 870 | this.parallelDoubleStreamSupport 871 | .peek(d -> threadRef.set(currentThread())) 872 | .noneMatch(d -> true); 873 | 874 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 875 | } 876 | 877 | @Test 878 | void findFirst() { 879 | OptionalDouble result = this.parallelStreamSupportMock.findFirst(); 880 | 881 | verify(this.delegateMock).findFirst(); 882 | assertEquals(OptionalDouble.of(42), result); 883 | } 884 | 885 | @Test 886 | void findFirstSequential() { 887 | this.parallelDoubleStreamSupport.sequential(); 888 | Thread thisThread = currentThread(); 889 | AtomicReference threadRef = new AtomicReference<>(); 890 | 891 | this.parallelDoubleStreamSupport 892 | .peek(d -> threadRef.set(currentThread())) 893 | .findFirst(); 894 | 895 | assertEquals(thisThread, threadRef.get()); 896 | } 897 | 898 | @Test 899 | void findFirstParallel() { 900 | this.parallelDoubleStreamSupport.parallel(); 901 | AtomicReference threadRef = new AtomicReference<>(); 902 | 903 | this.parallelDoubleStreamSupport 904 | .peek(d -> threadRef.set(currentThread())) 905 | .findFirst(); 906 | 907 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 908 | } 909 | 910 | @Test 911 | void findAny() { 912 | OptionalDouble result = this.parallelStreamSupportMock.findAny(); 913 | 914 | verify(this.delegateMock).findAny(); 915 | assertEquals(OptionalDouble.of(42), result); 916 | } 917 | 918 | @Test 919 | void findAnytSequential() { 920 | this.parallelDoubleStreamSupport.sequential(); 921 | Thread thisThread = currentThread(); 922 | AtomicReference threadRef = new AtomicReference<>(); 923 | 924 | this.parallelDoubleStreamSupport 925 | .peek(d -> threadRef.set(currentThread())) 926 | .findAny(); 927 | 928 | assertEquals(thisThread, threadRef.get()); 929 | } 930 | 931 | @Test 932 | void findAnyParallel() { 933 | this.parallelDoubleStreamSupport.parallel(); 934 | AtomicReference threadRef = new AtomicReference<>(); 935 | 936 | this.parallelDoubleStreamSupport 937 | .peek(d -> threadRef.set(currentThread())) 938 | .findAny(); 939 | 940 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 941 | } 942 | 943 | @Test 944 | void boxed() { 945 | Stream stream = this.parallelStreamSupportMock.boxed(); 946 | 947 | verify(this.delegateMock).boxed(); 948 | assertThat(stream, instanceOf(ParallelStreamSupport.class)); 949 | assertSame(this.mappedDelegateMock, ParallelStreamSupport.class.cast(stream).delegate); 950 | assertSame(this.workerPool, ParallelStreamSupport.class.cast(stream).workerPool); 951 | } 952 | 953 | @Override 954 | @Test 955 | void iterator() { 956 | PrimitiveIterator.OfDouble iterator = this.parallelStreamSupportMock.iterator(); 957 | 958 | verify(this.delegateMock).iterator(); 959 | assertSame(this.iteratorMock, iterator); 960 | } 961 | 962 | @Override 963 | @Test 964 | void spliterator() { 965 | Spliterator.OfDouble spliterator = this.parallelStreamSupportMock.spliterator(); 966 | 967 | verify(this.delegateMock).spliterator(); 968 | assertSame(this.spliteratorMock, spliterator); 969 | } 970 | } 971 | -------------------------------------------------------------------------------- /src/test/java/com/github/ferstl/streams/ParallelIntStreamSupportTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Stefan Ferstl 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.github.ferstl.streams; 23 | 24 | import java.util.ArrayList; 25 | import java.util.IntSummaryStatistics; 26 | import java.util.OptionalDouble; 27 | import java.util.OptionalInt; 28 | import java.util.PrimitiveIterator; 29 | import java.util.Spliterator; 30 | import java.util.concurrent.ForkJoinPool; 31 | import java.util.concurrent.ForkJoinWorkerThread; 32 | import java.util.concurrent.atomic.AtomicReference; 33 | import java.util.function.BiConsumer; 34 | import java.util.function.IntBinaryOperator; 35 | import java.util.function.IntConsumer; 36 | import java.util.function.IntFunction; 37 | import java.util.function.IntPredicate; 38 | import java.util.function.IntSupplier; 39 | import java.util.function.IntToDoubleFunction; 40 | import java.util.function.IntToLongFunction; 41 | import java.util.function.IntUnaryOperator; 42 | import java.util.function.ObjIntConsumer; 43 | import java.util.function.Supplier; 44 | import java.util.stream.DoubleStream; 45 | import java.util.stream.IntStream; 46 | import java.util.stream.IntStream.Builder; 47 | import java.util.stream.LongStream; 48 | import java.util.stream.Stream; 49 | import org.junit.jupiter.api.BeforeEach; 50 | import org.junit.jupiter.api.Test; 51 | import static java.lang.Thread.currentThread; 52 | import static org.hamcrest.MatcherAssert.assertThat; 53 | import static org.hamcrest.Matchers.instanceOf; 54 | import static org.junit.jupiter.api.Assertions.assertArrayEquals; 55 | import static org.junit.jupiter.api.Assertions.assertEquals; 56 | import static org.junit.jupiter.api.Assertions.assertFalse; 57 | import static org.junit.jupiter.api.Assertions.assertSame; 58 | import static org.junit.jupiter.api.Assertions.assertThrows; 59 | import static org.junit.jupiter.api.Assertions.assertTrue; 60 | import static org.mockito.ArgumentMatchers.any; 61 | import static org.mockito.ArgumentMatchers.anyInt; 62 | import static org.mockito.Mockito.mock; 63 | import static org.mockito.Mockito.verify; 64 | import static org.mockito.Mockito.when; 65 | 66 | @SuppressWarnings("ResultOfMethodCallIgnored") 67 | public class ParallelIntStreamSupportTest extends AbstractParallelStreamSupportTest { 68 | 69 | private Stream mappedDelegateMock; 70 | private IntStream mappedIntDelegateMock; 71 | private LongStream mappedLongDelegateMock; 72 | private DoubleStream mappedDoubleDelegateMock; 73 | private PrimitiveIterator.OfInt iteratorMock; 74 | private Spliterator.OfInt spliteratorMock; 75 | private int[] toArrayResult; 76 | private IntSummaryStatistics summaryStatistics; 77 | 78 | private ParallelIntStreamSupport parallelIntStreamSupport; 79 | 80 | 81 | @Override 82 | protected ParallelIntStreamSupport createParallelStreamSupportMock(ForkJoinPool workerPool) { 83 | return new ParallelIntStreamSupport(mock(IntStream.class), workerPool); 84 | } 85 | 86 | @BeforeEach 87 | @SuppressWarnings({"unchecked", "rawtypes"}) 88 | void init() { 89 | // Precondition for all tests 90 | assertFalse(currentThread() instanceof ForkJoinWorkerThread, "This test must not run in a ForkJoinPool"); 91 | 92 | this.mappedDelegateMock = mock(Stream.class); 93 | this.mappedIntDelegateMock = mock(IntStream.class); 94 | this.mappedLongDelegateMock = mock(LongStream.class); 95 | this.mappedDoubleDelegateMock = mock(DoubleStream.class); 96 | this.iteratorMock = mock(PrimitiveIterator.OfInt.class); 97 | this.spliteratorMock = mock(Spliterator.OfInt.class); 98 | this.toArrayResult = new int[0]; 99 | this.summaryStatistics = new IntSummaryStatistics(); 100 | 101 | when(this.delegateMock.map(any())).thenReturn(this.mappedIntDelegateMock); 102 | when(this.delegateMock.mapToObj(any())).thenReturn((Stream) this.mappedDelegateMock); 103 | when(this.delegateMock.mapToLong(any())).thenReturn(this.mappedLongDelegateMock); 104 | when(this.delegateMock.mapToDouble(any())).thenReturn(this.mappedDoubleDelegateMock); 105 | when(this.delegateMock.flatMap(any())).thenReturn(this.mappedIntDelegateMock); 106 | when(this.delegateMock.iterator()).thenReturn(this.iteratorMock); 107 | when(this.delegateMock.spliterator()).thenReturn(this.spliteratorMock); 108 | when(this.delegateMock.isParallel()).thenReturn(false); 109 | when(this.delegateMock.toArray()).thenReturn(this.toArrayResult); 110 | when(this.delegateMock.reduce(anyInt(), any())).thenReturn(42); 111 | when(this.delegateMock.reduce(any())).thenReturn(OptionalInt.of(42)); 112 | when(this.delegateMock.collect(any(), any(), any())).thenReturn("collect"); 113 | when(this.delegateMock.sum()).thenReturn(42); 114 | when(this.delegateMock.min()).thenReturn(OptionalInt.of(42)); 115 | when(this.delegateMock.max()).thenReturn(OptionalInt.of(42)); 116 | when(this.delegateMock.count()).thenReturn(42L); 117 | when(this.delegateMock.average()).thenReturn(OptionalDouble.of(42.0)); 118 | when(this.delegateMock.summaryStatistics()).thenReturn(this.summaryStatistics); 119 | when(this.delegateMock.anyMatch(any())).thenReturn(true); 120 | when(this.delegateMock.allMatch(any())).thenReturn(true); 121 | when(this.delegateMock.noneMatch(any())).thenReturn(true); 122 | when(this.delegateMock.findFirst()).thenReturn(OptionalInt.of(42)); 123 | when(this.delegateMock.findAny()).thenReturn(OptionalInt.of(42)); 124 | when(this.delegateMock.asLongStream()).thenReturn(this.mappedLongDelegateMock); 125 | when(this.delegateMock.asDoubleStream()).thenReturn(this.mappedDoubleDelegateMock); 126 | when(this.delegateMock.boxed()).thenReturn((Stream) this.mappedDelegateMock); 127 | 128 | IntStream delegate = IntStream.of(1).parallel(); 129 | this.parallelIntStreamSupport = new ParallelIntStreamSupport(delegate, this.workerPool); 130 | } 131 | 132 | @Test 133 | void parallelStreamWithArray() { 134 | IntStream stream = ParallelIntStreamSupport.parallelStream(new int[]{42}, this.workerPool); 135 | 136 | assertThat(stream, instanceOf(ParallelIntStreamSupport.class)); 137 | assertTrue(stream.isParallel()); 138 | assertEquals(OptionalInt.of(42), stream.findAny()); 139 | } 140 | 141 | @Test 142 | void parallelStreamWithNullArray() { 143 | assertThrows(NullPointerException.class, () -> ParallelIntStreamSupport.parallelStream((int[]) null, this.workerPool)); 144 | } 145 | 146 | @Test 147 | void parallelStreamSupportWithSpliterator() { 148 | Spliterator.OfInt spliterator = IntStream.of(42).spliterator(); 149 | IntStream stream = ParallelIntStreamSupport.parallelStream(spliterator, this.workerPool); 150 | 151 | assertThat(stream, instanceOf(ParallelIntStreamSupport.class)); 152 | assertTrue(stream.isParallel()); 153 | assertEquals(OptionalInt.of(42), stream.findAny()); 154 | } 155 | 156 | @Test 157 | void parallelStreamSupportWithNullSpliterator() { 158 | assertThrows(NullPointerException.class, () -> ParallelIntStreamSupport.parallelStream((Spliterator.OfInt) null, this.workerPool)); 159 | } 160 | 161 | @Test 162 | void parallelStreamSupportWithSpliteratorSupplier() { 163 | Supplier supplier = () -> IntStream.of(42).spliterator(); 164 | IntStream stream = ParallelIntStreamSupport.parallelStream(supplier, 0, this.workerPool); 165 | 166 | assertThat(stream, instanceOf(ParallelIntStreamSupport.class)); 167 | assertTrue(stream.isParallel()); 168 | assertEquals(OptionalInt.of(42), stream.findAny()); 169 | } 170 | 171 | @Test 172 | void parallelStreamSupportWithNullSpliteratorSupplier() { 173 | assertThrows(NullPointerException.class, () -> ParallelIntStreamSupport.parallelStream(null, 0, this.workerPool)); 174 | } 175 | 176 | @Test 177 | void parallelStreamWithBuilder() { 178 | Builder builder = IntStream.builder(); 179 | builder.accept(42); 180 | IntStream stream = ParallelIntStreamSupport.parallelStream(builder, this.workerPool); 181 | 182 | assertThat(stream, instanceOf(ParallelIntStreamSupport.class)); 183 | assertTrue(stream.isParallel()); 184 | assertEquals(OptionalInt.of(42), stream.findAny()); 185 | } 186 | 187 | @Test 188 | void parallelStreamWithNullBuilder() { 189 | assertThrows(NullPointerException.class, () -> ParallelIntStreamSupport.parallelStream((Builder) null, this.workerPool)); 190 | } 191 | 192 | @Test 193 | void iterate() { 194 | IntUnaryOperator operator = a -> a; 195 | IntStream stream = ParallelIntStreamSupport.iterate(42, operator, this.workerPool); 196 | 197 | assertThat(stream, instanceOf(ParallelIntStreamSupport.class)); 198 | assertTrue(stream.isParallel()); 199 | assertEquals(OptionalInt.of(42), stream.findAny()); 200 | } 201 | 202 | @Test 203 | void iterateWithNullOperator() { 204 | assertThrows(NullPointerException.class, () -> ParallelIntStreamSupport.iterate(42, null, this.workerPool)); 205 | } 206 | 207 | @Test 208 | void generate() { 209 | IntSupplier supplier = () -> 42; 210 | IntStream stream = ParallelIntStreamSupport.generate(supplier, this.workerPool); 211 | 212 | assertThat(stream, instanceOf(ParallelIntStreamSupport.class)); 213 | assertTrue(stream.isParallel()); 214 | assertEquals(OptionalInt.of(42), stream.findAny()); 215 | } 216 | 217 | @Test 218 | void generateWithNullSupplier() { 219 | assertThrows(NullPointerException.class, () -> ParallelIntStreamSupport.generate(null, this.workerPool)); 220 | } 221 | 222 | @Test 223 | void range() { 224 | IntStream stream = ParallelIntStreamSupport.range(0, 5, this.workerPool); 225 | 226 | assertThat(stream, instanceOf(ParallelIntStreamSupport.class)); 227 | assertTrue(stream.isParallel()); 228 | assertArrayEquals(stream.toArray(), new int[]{0, 1, 2, 3, 4}); 229 | } 230 | 231 | @Test 232 | void rangeClosed() { 233 | IntStream stream = ParallelIntStreamSupport.rangeClosed(0, 5, this.workerPool); 234 | 235 | assertThat(stream, instanceOf(ParallelIntStreamSupport.class)); 236 | assertTrue(stream.isParallel()); 237 | assertArrayEquals(stream.toArray(), new int[]{0, 1, 2, 3, 4, 5}); 238 | } 239 | 240 | @Test 241 | void concat() { 242 | IntStream a = IntStream.of(42); 243 | IntStream b = IntStream.of(43); 244 | IntStream stream = ParallelIntStreamSupport.concat(a, b, this.workerPool); 245 | 246 | assertThat(stream, instanceOf(ParallelIntStreamSupport.class)); 247 | assertTrue(stream.isParallel()); 248 | assertArrayEquals(stream.toArray(), new int[]{42, 43}); 249 | } 250 | 251 | @Test 252 | void concatWithNullStreamA() { 253 | assertThrows(NullPointerException.class, () -> ParallelIntStreamSupport.concat(null, IntStream.of(42), this.workerPool)); 254 | } 255 | 256 | @Test 257 | void concatWithNullStreamB() { 258 | assertThrows(NullPointerException.class, () -> ParallelIntStreamSupport.concat(IntStream.of(42), null, this.workerPool)); 259 | } 260 | 261 | @Test 262 | void filter() { 263 | IntPredicate p = i -> true; 264 | IntStream stream = this.parallelStreamSupportMock.filter(p); 265 | 266 | verify(this.delegateMock).filter(p); 267 | assertSame(this.parallelStreamSupportMock, stream); 268 | } 269 | 270 | @Test 271 | void map() { 272 | IntUnaryOperator f = i -> 42; 273 | IntStream stream = this.parallelStreamSupportMock.map(f); 274 | 275 | verify(this.delegateMock).map(f); 276 | assertThat(stream, instanceOf(ParallelIntStreamSupport.class)); 277 | assertSame(((ParallelIntStreamSupport) stream).delegate, this.mappedIntDelegateMock); 278 | assertSame(((ParallelIntStreamSupport) stream).workerPool, this.workerPool); 279 | } 280 | 281 | @Test 282 | void mapToObj() { 283 | IntFunction f = i -> "x"; 284 | Stream stream = this.parallelStreamSupportMock.mapToObj(f); 285 | 286 | verify(this.delegateMock).mapToObj(f); 287 | assertThat(stream, instanceOf(ParallelStreamSupport.class)); 288 | assertSame(((ParallelStreamSupport) stream).delegate, this.mappedDelegateMock); 289 | assertSame(((ParallelStreamSupport) stream).workerPool, this.workerPool); 290 | } 291 | 292 | @Test 293 | void mapToLong() { 294 | IntToLongFunction f = i -> 1L; 295 | LongStream stream = this.parallelStreamSupportMock.mapToLong(f); 296 | 297 | verify(this.delegateMock).mapToLong(f); 298 | assertThat(stream, instanceOf(ParallelLongStreamSupport.class)); 299 | assertSame(((ParallelLongStreamSupport) stream).delegate, this.mappedLongDelegateMock); 300 | assertSame(((ParallelLongStreamSupport) stream).workerPool, this.workerPool); 301 | } 302 | 303 | @Test 304 | void mapToDouble() { 305 | IntToDoubleFunction f = i -> 1.0; 306 | DoubleStream stream = this.parallelStreamSupportMock.mapToDouble(f); 307 | 308 | verify(this.delegateMock).mapToDouble(f); 309 | assertThat(stream, instanceOf(ParallelDoubleStreamSupport.class)); 310 | assertSame(((ParallelDoubleStreamSupport) stream).delegate, this.mappedDoubleDelegateMock); 311 | assertSame(((ParallelDoubleStreamSupport) stream).workerPool, this.workerPool); 312 | } 313 | 314 | @Test 315 | void flatMap() { 316 | IntFunction f = i -> IntStream.of(1); 317 | IntStream stream = this.parallelStreamSupportMock.flatMap(f); 318 | 319 | verify(this.delegateMock).flatMap(f); 320 | assertThat(stream, instanceOf(ParallelIntStreamSupport.class)); 321 | assertSame(((ParallelIntStreamSupport) stream).delegate, this.mappedIntDelegateMock); 322 | } 323 | 324 | @Test 325 | void distinct() { 326 | IntStream stream = this.parallelStreamSupportMock.distinct(); 327 | 328 | verify(this.delegateMock).distinct(); 329 | assertSame(this.parallelStreamSupportMock, stream); 330 | } 331 | 332 | @Test 333 | void sorted() { 334 | IntStream stream = this.parallelStreamSupportMock.sorted(); 335 | 336 | verify(this.delegateMock).sorted(); 337 | assertSame(this.parallelStreamSupportMock, stream); 338 | } 339 | 340 | @Test 341 | void peek() { 342 | IntConsumer c = i -> { 343 | }; 344 | IntStream stream = this.parallelStreamSupportMock.peek(c); 345 | 346 | verify(this.delegateMock).peek(c); 347 | assertSame(this.parallelStreamSupportMock, stream); 348 | } 349 | 350 | @Test 351 | void limit() { 352 | IntStream stream = this.parallelStreamSupportMock.limit(5); 353 | 354 | verify(this.delegateMock).limit(5); 355 | assertSame(this.parallelStreamSupportMock, stream); 356 | } 357 | 358 | @Test 359 | void skip() { 360 | IntStream stream = this.parallelStreamSupportMock.skip(5); 361 | 362 | verify(this.delegateMock).skip(5); 363 | assertSame(this.parallelStreamSupportMock, stream); 364 | } 365 | 366 | @Test 367 | void takeWhile() { 368 | IntPredicate predicate = x -> true; 369 | IntStream stream = this.parallelStreamSupportMock.takeWhile(predicate); 370 | 371 | verify(this.delegateMock).takeWhile(predicate); 372 | assertSame(this.parallelStreamSupportMock, stream); 373 | } 374 | 375 | @Test 376 | void dropWhile() { 377 | IntPredicate predicate = x -> true; 378 | IntStream stream = this.parallelStreamSupportMock.dropWhile(predicate); 379 | 380 | verify(this.delegateMock).dropWhile(predicate); 381 | assertSame(this.parallelStreamSupportMock, stream); 382 | } 383 | 384 | @Test 385 | void forEach() { 386 | IntConsumer c = i -> { 387 | }; 388 | this.parallelStreamSupportMock.forEach(c); 389 | 390 | verify(this.delegateMock).forEach(c); 391 | } 392 | 393 | @Test 394 | void forEachSequential() { 395 | this.parallelIntStreamSupport.sequential(); 396 | Thread thisThread = currentThread(); 397 | AtomicReference threadRef = new AtomicReference<>(); 398 | 399 | this.parallelIntStreamSupport.forEach(i -> threadRef.set(currentThread())); 400 | 401 | assertEquals(thisThread, threadRef.get()); 402 | } 403 | 404 | @Test 405 | void forEachParallel() { 406 | this.parallelIntStreamSupport.parallel(); 407 | AtomicReference threadRef = new AtomicReference<>(); 408 | 409 | this.parallelIntStreamSupport.forEach(i -> threadRef.set(currentThread())); 410 | 411 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 412 | } 413 | 414 | @Test 415 | void forEachOrdered() { 416 | IntConsumer c = i -> { 417 | }; 418 | this.parallelStreamSupportMock.forEachOrdered(c); 419 | 420 | verify(this.delegateMock).forEachOrdered(c); 421 | } 422 | 423 | @Test 424 | void forEachOrderedSequential() { 425 | this.parallelIntStreamSupport.sequential(); 426 | Thread thisThread = currentThread(); 427 | AtomicReference threadRef = new AtomicReference<>(); 428 | 429 | this.parallelIntStreamSupport.forEachOrdered(i -> threadRef.set(currentThread())); 430 | 431 | assertEquals(thisThread, threadRef.get()); 432 | } 433 | 434 | @Test 435 | void forEachOrderedParallel() { 436 | this.parallelIntStreamSupport.parallel(); 437 | AtomicReference threadRef = new AtomicReference<>(); 438 | 439 | this.parallelIntStreamSupport.forEachOrdered(i -> threadRef.set(currentThread())); 440 | 441 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 442 | } 443 | 444 | @Test 445 | void toArray() { 446 | int[] array = this.parallelStreamSupportMock.toArray(); 447 | 448 | verify(this.delegateMock).toArray(); 449 | assertSame(this.toArrayResult, array); 450 | } 451 | 452 | @Test 453 | void toArraySequential() { 454 | this.parallelIntStreamSupport.sequential(); 455 | Thread thisThread = currentThread(); 456 | AtomicReference threadRef = new AtomicReference<>(); 457 | 458 | this.parallelIntStreamSupport 459 | .peek(i -> threadRef.set(currentThread())) 460 | .toArray(); 461 | 462 | assertEquals(thisThread, threadRef.get()); 463 | } 464 | 465 | @Test 466 | void toArrayParallel() { 467 | this.parallelIntStreamSupport.parallel(); 468 | AtomicReference threadRef = new AtomicReference<>(); 469 | 470 | this.parallelIntStreamSupport 471 | .peek(i -> threadRef.set(currentThread())) 472 | .toArray(); 473 | 474 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 475 | } 476 | 477 | @Test 478 | void reduceWithIdentityAndAccumulator() { 479 | IntBinaryOperator accumulator = (a, b) -> b; 480 | int result = this.parallelStreamSupportMock.reduce(0, accumulator); 481 | 482 | verify(this.delegateMock).reduce(0, accumulator); 483 | assertEquals(42, result); 484 | } 485 | 486 | @Test 487 | void reduceWithIdentityAndAccumulatorSequential() { 488 | this.parallelIntStreamSupport.sequential(); 489 | IntBinaryOperator accumulator = (a, b) -> b; 490 | Thread thisThread = currentThread(); 491 | AtomicReference threadRef = new AtomicReference<>(); 492 | 493 | this.parallelIntStreamSupport 494 | .peek(i -> threadRef.set(currentThread())) 495 | .reduce(0, accumulator); 496 | 497 | assertEquals(thisThread, threadRef.get()); 498 | } 499 | 500 | @Test 501 | void reduceWithIdentityAndAccumulatorParallel() { 502 | this.parallelIntStreamSupport.parallel(); 503 | IntBinaryOperator accumulator = (a, b) -> b; 504 | AtomicReference threadRef = new AtomicReference<>(); 505 | 506 | this.parallelIntStreamSupport 507 | .peek(i -> threadRef.set(currentThread())) 508 | .reduce(0, accumulator); 509 | 510 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 511 | } 512 | 513 | @Test 514 | void reduceWithAccumulator() { 515 | IntBinaryOperator accumulator = (a, b) -> b; 516 | OptionalInt result = this.parallelStreamSupportMock.reduce(accumulator); 517 | 518 | verify(this.delegateMock).reduce(accumulator); 519 | assertEquals(OptionalInt.of(42), result); 520 | } 521 | 522 | @Test 523 | void reduceWithAccumulatorSequential() { 524 | this.parallelIntStreamSupport.sequential(); 525 | IntBinaryOperator accumulator = (a, b) -> b; 526 | Thread thisThread = currentThread(); 527 | AtomicReference threadRef = new AtomicReference<>(); 528 | 529 | this.parallelIntStreamSupport 530 | .peek(i -> threadRef.set(currentThread())) 531 | .reduce(accumulator); 532 | 533 | assertEquals(thisThread, threadRef.get()); 534 | } 535 | 536 | @Test 537 | void reduceWithAccumulatorParallel() { 538 | this.parallelIntStreamSupport.parallel(); 539 | IntBinaryOperator accumulator = (a, b) -> b; 540 | AtomicReference threadRef = new AtomicReference<>(); 541 | 542 | this.parallelIntStreamSupport 543 | .peek(i -> threadRef.set(currentThread())) 544 | .reduce(accumulator); 545 | 546 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 547 | } 548 | 549 | @Test 550 | void collectWithSupplierAndAccumulatorAndCombiner() { 551 | Supplier supplier = () -> "x"; 552 | ObjIntConsumer accumulator = (a, b) -> { 553 | }; 554 | BiConsumer combiner = (a, b) -> { 555 | }; 556 | 557 | String result = this.parallelStreamSupportMock.collect(supplier, accumulator, combiner); 558 | 559 | verify(this.delegateMock).collect(supplier, accumulator, combiner); 560 | assertEquals("collect", result); 561 | } 562 | 563 | @Test 564 | void collectWithSupplierAndAccumulatorAndCombinerSequential() { 565 | this.parallelIntStreamSupport.sequential(); 566 | Thread thisThread = currentThread(); 567 | AtomicReference threadRef = new AtomicReference<>(); 568 | 569 | this.parallelIntStreamSupport 570 | .peek(i -> threadRef.set(currentThread())) 571 | .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); 572 | 573 | assertEquals(thisThread, threadRef.get()); 574 | } 575 | 576 | @Test 577 | void collectWithSupplierAndAccumulatorAndCombinerParallel() { 578 | this.parallelIntStreamSupport.parallel(); 579 | AtomicReference threadRef = new AtomicReference<>(); 580 | 581 | this.parallelIntStreamSupport 582 | .peek(i -> threadRef.set(currentThread())) 583 | .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); 584 | 585 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 586 | } 587 | 588 | @Test 589 | void sum() { 590 | int result = this.parallelStreamSupportMock.sum(); 591 | 592 | verify(this.delegateMock).sum(); 593 | assertEquals(42, result); 594 | } 595 | 596 | @Test 597 | void sumSequential() { 598 | this.parallelIntStreamSupport.sequential(); 599 | Thread thisThread = currentThread(); 600 | AtomicReference threadRef = new AtomicReference<>(); 601 | 602 | this.parallelIntStreamSupport 603 | .peek(i -> threadRef.set(currentThread())) 604 | .sum(); 605 | 606 | assertEquals(thisThread, threadRef.get()); 607 | } 608 | 609 | @Test 610 | void sumParallel() { 611 | this.parallelIntStreamSupport.parallel(); 612 | AtomicReference threadRef = new AtomicReference<>(); 613 | 614 | this.parallelIntStreamSupport 615 | .peek(i -> threadRef.set(currentThread())) 616 | .sum(); 617 | 618 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 619 | } 620 | 621 | @Test 622 | void min() { 623 | OptionalInt result = this.parallelStreamSupportMock.min(); 624 | 625 | verify(this.delegateMock).min(); 626 | assertEquals(OptionalInt.of(42), result); 627 | } 628 | 629 | @Test 630 | void minSequential() { 631 | this.parallelIntStreamSupport.sequential(); 632 | Thread thisThread = currentThread(); 633 | AtomicReference threadRef = new AtomicReference<>(); 634 | 635 | this.parallelIntStreamSupport 636 | .peek(i -> threadRef.set(currentThread())) 637 | .min(); 638 | 639 | assertEquals(thisThread, threadRef.get()); 640 | } 641 | 642 | @Test 643 | void minParallel() { 644 | this.parallelIntStreamSupport.parallel(); 645 | AtomicReference threadRef = new AtomicReference<>(); 646 | 647 | this.parallelIntStreamSupport 648 | .peek(i -> threadRef.set(currentThread())) 649 | .min(); 650 | 651 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 652 | } 653 | 654 | @Test 655 | void max() { 656 | OptionalInt result = this.parallelStreamSupportMock.max(); 657 | 658 | verify(this.delegateMock).max(); 659 | assertEquals(OptionalInt.of(42), result); 660 | } 661 | 662 | @Test 663 | void maxSequential() { 664 | this.parallelIntStreamSupport.sequential(); 665 | Thread thisThread = currentThread(); 666 | AtomicReference threadRef = new AtomicReference<>(); 667 | 668 | this.parallelIntStreamSupport 669 | .peek(i -> threadRef.set(currentThread())) 670 | .max(); 671 | 672 | assertEquals(thisThread, threadRef.get()); 673 | } 674 | 675 | @Test 676 | void maxParallel() { 677 | this.parallelIntStreamSupport.parallel(); 678 | AtomicReference threadRef = new AtomicReference<>(); 679 | 680 | this.parallelIntStreamSupport 681 | .peek(i -> threadRef.set(currentThread())) 682 | .max(); 683 | 684 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 685 | } 686 | 687 | @Test 688 | void count() { 689 | long count = this.parallelStreamSupportMock.count(); 690 | 691 | verify(this.delegateMock).count(); 692 | assertEquals(42L, count); 693 | } 694 | 695 | @Test 696 | void countSequential() { 697 | this.parallelIntStreamSupport.sequential(); 698 | Thread thisThread = currentThread(); 699 | AtomicReference threadRef = new AtomicReference<>(); 700 | 701 | this.parallelIntStreamSupport 702 | .filter(i -> { 703 | // Don't use peek() in combination with count(). See Javadoc. 704 | threadRef.set(currentThread()); 705 | return true; 706 | }).count(); 707 | 708 | assertEquals(thisThread, threadRef.get()); 709 | } 710 | 711 | @Test 712 | void countParallel() { 713 | this.parallelIntStreamSupport.parallel(); 714 | AtomicReference threadRef = new AtomicReference<>(); 715 | 716 | this.parallelIntStreamSupport 717 | // Don't use peek() in combination with count(). See Javadoc. 718 | .filter(i -> { 719 | threadRef.set(currentThread()); 720 | return true; 721 | }).count(); 722 | 723 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 724 | } 725 | 726 | @Test 727 | void average() { 728 | OptionalDouble result = this.parallelStreamSupportMock.average(); 729 | 730 | verify(this.delegateMock).average(); 731 | assertEquals(OptionalDouble.of(42.0), result); 732 | } 733 | 734 | @Test 735 | void averageSequential() { 736 | this.parallelIntStreamSupport.sequential(); 737 | Thread thisThread = currentThread(); 738 | AtomicReference threadRef = new AtomicReference<>(); 739 | 740 | this.parallelIntStreamSupport 741 | .peek(i -> threadRef.set(currentThread())) 742 | .average(); 743 | 744 | assertEquals(thisThread, threadRef.get()); 745 | } 746 | 747 | @Test 748 | void averageParallel() { 749 | this.parallelIntStreamSupport.parallel(); 750 | AtomicReference threadRef = new AtomicReference<>(); 751 | 752 | this.parallelIntStreamSupport 753 | .peek(i -> threadRef.set(currentThread())) 754 | .average(); 755 | 756 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 757 | } 758 | 759 | @Test 760 | void summaryStatistics() { 761 | IntSummaryStatistics result = this.parallelStreamSupportMock.summaryStatistics(); 762 | 763 | verify(this.delegateMock).summaryStatistics(); 764 | assertEquals(this.summaryStatistics, result); 765 | } 766 | 767 | @Test 768 | void summaryStatisticsSequential() { 769 | this.parallelIntStreamSupport.sequential(); 770 | Thread thisThread = currentThread(); 771 | AtomicReference threadRef = new AtomicReference<>(); 772 | 773 | this.parallelIntStreamSupport 774 | .peek(i -> threadRef.set(currentThread())) 775 | .summaryStatistics(); 776 | 777 | assertEquals(thisThread, threadRef.get()); 778 | } 779 | 780 | @Test 781 | void summaryStatisticsParallel() { 782 | this.parallelIntStreamSupport.parallel(); 783 | AtomicReference threadRef = new AtomicReference<>(); 784 | 785 | this.parallelIntStreamSupport 786 | .peek(i -> threadRef.set(currentThread())) 787 | .summaryStatistics(); 788 | 789 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 790 | } 791 | 792 | @Test 793 | void anyMatch() { 794 | IntPredicate p = i -> true; 795 | 796 | boolean result = this.parallelStreamSupportMock.anyMatch(p); 797 | 798 | verify(this.delegateMock).anyMatch(p); 799 | assertTrue(result); 800 | } 801 | 802 | @Test 803 | void anyMatchSequential() { 804 | this.parallelIntStreamSupport.sequential(); 805 | Thread thisThread = currentThread(); 806 | AtomicReference threadRef = new AtomicReference<>(); 807 | 808 | this.parallelIntStreamSupport 809 | .peek(i -> threadRef.set(currentThread())) 810 | .anyMatch(i -> true); 811 | 812 | assertEquals(thisThread, threadRef.get()); 813 | } 814 | 815 | @Test 816 | void anyMatchParallel() { 817 | this.parallelIntStreamSupport.parallel(); 818 | AtomicReference threadRef = new AtomicReference<>(); 819 | 820 | this.parallelIntStreamSupport 821 | .peek(i -> threadRef.set(currentThread())) 822 | .anyMatch(i -> true); 823 | 824 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 825 | } 826 | 827 | @Test 828 | void allMatch() { 829 | IntPredicate p = i -> true; 830 | 831 | boolean result = this.parallelStreamSupportMock.allMatch(p); 832 | 833 | verify(this.delegateMock).allMatch(p); 834 | assertTrue(result); 835 | } 836 | 837 | @Test 838 | void allMatchSequential() { 839 | this.parallelIntStreamSupport.sequential(); 840 | Thread thisThread = currentThread(); 841 | AtomicReference threadRef = new AtomicReference<>(); 842 | 843 | this.parallelIntStreamSupport 844 | .peek(i -> threadRef.set(currentThread())) 845 | .allMatch(i -> true); 846 | 847 | assertEquals(thisThread, threadRef.get()); 848 | } 849 | 850 | @Test 851 | void allMatchParallel() { 852 | this.parallelIntStreamSupport.parallel(); 853 | AtomicReference threadRef = new AtomicReference<>(); 854 | 855 | this.parallelIntStreamSupport 856 | .peek(i -> threadRef.set(currentThread())) 857 | .allMatch(i -> true); 858 | 859 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 860 | } 861 | 862 | @Test 863 | void noneMatch() { 864 | IntPredicate p = i -> true; 865 | 866 | boolean result = this.parallelStreamSupportMock.noneMatch(p); 867 | 868 | verify(this.delegateMock).noneMatch(p); 869 | assertTrue(result); 870 | } 871 | 872 | @Test 873 | void noneMatchSequential() { 874 | this.parallelIntStreamSupport.sequential(); 875 | Thread thisThread = currentThread(); 876 | AtomicReference threadRef = new AtomicReference<>(); 877 | 878 | this.parallelIntStreamSupport 879 | .peek(i -> threadRef.set(currentThread())) 880 | .noneMatch(i -> true); 881 | 882 | assertEquals(thisThread, threadRef.get()); 883 | } 884 | 885 | @Test 886 | void noneMatchParallel() { 887 | this.parallelIntStreamSupport.parallel(); 888 | AtomicReference threadRef = new AtomicReference<>(); 889 | 890 | this.parallelIntStreamSupport 891 | .peek(i -> threadRef.set(currentThread())) 892 | .noneMatch(i -> true); 893 | 894 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 895 | } 896 | 897 | @Test 898 | void findFirst() { 899 | OptionalInt result = this.parallelStreamSupportMock.findFirst(); 900 | 901 | verify(this.delegateMock).findFirst(); 902 | assertEquals(OptionalInt.of(42), result); 903 | } 904 | 905 | @Test 906 | void findFirstSequential() { 907 | this.parallelIntStreamSupport.sequential(); 908 | Thread thisThread = currentThread(); 909 | AtomicReference threadRef = new AtomicReference<>(); 910 | 911 | this.parallelIntStreamSupport 912 | .peek(i -> threadRef.set(currentThread())) 913 | .findFirst(); 914 | 915 | assertEquals(thisThread, threadRef.get()); 916 | } 917 | 918 | @Test 919 | void findFirstParallel() { 920 | this.parallelIntStreamSupport.parallel(); 921 | AtomicReference threadRef = new AtomicReference<>(); 922 | 923 | this.parallelIntStreamSupport 924 | .peek(i -> threadRef.set(currentThread())) 925 | .findFirst(); 926 | 927 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 928 | } 929 | 930 | @Test 931 | void findAny() { 932 | OptionalInt result = this.parallelStreamSupportMock.findAny(); 933 | 934 | verify(this.delegateMock).findAny(); 935 | assertEquals(OptionalInt.of(42), result); 936 | } 937 | 938 | @Test 939 | void findAnytSequential() { 940 | this.parallelIntStreamSupport.sequential(); 941 | Thread thisThread = currentThread(); 942 | AtomicReference threadRef = new AtomicReference<>(); 943 | 944 | this.parallelIntStreamSupport 945 | .peek(i -> threadRef.set(currentThread())) 946 | .findAny(); 947 | 948 | assertEquals(thisThread, threadRef.get()); 949 | } 950 | 951 | @Test 952 | void findAnyParallel() { 953 | this.parallelIntStreamSupport.parallel(); 954 | AtomicReference threadRef = new AtomicReference<>(); 955 | 956 | this.parallelIntStreamSupport 957 | .peek(i -> threadRef.set(currentThread())) 958 | .findAny(); 959 | 960 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 961 | } 962 | 963 | @Test 964 | void asLongStream() { 965 | LongStream stream = this.parallelStreamSupportMock.asLongStream(); 966 | 967 | verify(this.delegateMock).asLongStream(); 968 | assertThat(stream, instanceOf(ParallelLongStreamSupport.class)); 969 | assertSame(this.mappedLongDelegateMock, ((ParallelLongStreamSupport) stream).delegate); 970 | assertSame(this.workerPool, ((ParallelLongStreamSupport) stream).workerPool); 971 | } 972 | 973 | @Test 974 | void asDoubleStream() { 975 | DoubleStream stream = this.parallelStreamSupportMock.asDoubleStream(); 976 | 977 | verify(this.delegateMock).asDoubleStream(); 978 | assertThat(stream, instanceOf(ParallelDoubleStreamSupport.class)); 979 | assertSame(this.mappedDoubleDelegateMock, ((ParallelDoubleStreamSupport) stream).delegate); 980 | assertSame(this.workerPool, ((ParallelDoubleStreamSupport) stream).workerPool); 981 | } 982 | 983 | @Test 984 | void boxed() { 985 | Stream stream = this.parallelStreamSupportMock.boxed(); 986 | 987 | verify(this.delegateMock).boxed(); 988 | assertThat(stream, instanceOf(ParallelStreamSupport.class)); 989 | assertSame(this.mappedDelegateMock, ((ParallelStreamSupport) stream).delegate); 990 | assertSame(this.workerPool, ((ParallelStreamSupport) stream).workerPool); 991 | } 992 | 993 | @Override 994 | @Test 995 | void iterator() { 996 | PrimitiveIterator.OfInt iterator = this.parallelStreamSupportMock.iterator(); 997 | 998 | verify(this.delegateMock).iterator(); 999 | assertSame(this.iteratorMock, iterator); 1000 | } 1001 | 1002 | @Override 1003 | @Test 1004 | void spliterator() { 1005 | Spliterator.OfInt spliterator = this.parallelStreamSupportMock.spliterator(); 1006 | 1007 | verify(this.delegateMock).spliterator(); 1008 | assertSame(this.spliteratorMock, spliterator); 1009 | } 1010 | } 1011 | -------------------------------------------------------------------------------- /src/test/java/com/github/ferstl/streams/ParallelLongStreamSupportTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2016 Stefan Ferstl 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to deal 6 | * in the Software without restriction, including without limitation the rights 7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | * copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | * THE SOFTWARE. 21 | */ 22 | package com.github.ferstl.streams; 23 | 24 | import java.util.ArrayList; 25 | import java.util.LongSummaryStatistics; 26 | import java.util.OptionalDouble; 27 | import java.util.OptionalLong; 28 | import java.util.PrimitiveIterator; 29 | import java.util.Spliterator; 30 | import java.util.concurrent.ForkJoinPool; 31 | import java.util.concurrent.ForkJoinWorkerThread; 32 | import java.util.concurrent.atomic.AtomicReference; 33 | import java.util.function.BiConsumer; 34 | import java.util.function.LongBinaryOperator; 35 | import java.util.function.LongConsumer; 36 | import java.util.function.LongFunction; 37 | import java.util.function.LongPredicate; 38 | import java.util.function.LongSupplier; 39 | import java.util.function.LongToDoubleFunction; 40 | import java.util.function.LongToIntFunction; 41 | import java.util.function.LongUnaryOperator; 42 | import java.util.function.ObjLongConsumer; 43 | import java.util.function.Supplier; 44 | import java.util.stream.DoubleStream; 45 | import java.util.stream.IntStream; 46 | import java.util.stream.LongStream; 47 | import java.util.stream.LongStream.Builder; 48 | import java.util.stream.Stream; 49 | import org.junit.jupiter.api.BeforeEach; 50 | import org.junit.jupiter.api.Test; 51 | import static java.lang.Thread.currentThread; 52 | import static org.hamcrest.MatcherAssert.assertThat; 53 | import static org.hamcrest.Matchers.instanceOf; 54 | import static org.junit.jupiter.api.Assertions.assertArrayEquals; 55 | import static org.junit.jupiter.api.Assertions.assertEquals; 56 | import static org.junit.jupiter.api.Assertions.assertFalse; 57 | import static org.junit.jupiter.api.Assertions.assertSame; 58 | import static org.junit.jupiter.api.Assertions.assertThrows; 59 | import static org.junit.jupiter.api.Assertions.assertTrue; 60 | import static org.mockito.ArgumentMatchers.any; 61 | import static org.mockito.ArgumentMatchers.anyLong; 62 | import static org.mockito.Mockito.mock; 63 | import static org.mockito.Mockito.verify; 64 | import static org.mockito.Mockito.when; 65 | 66 | @SuppressWarnings("ResultOfMethodCallIgnored") 67 | public class ParallelLongStreamSupportTest extends AbstractParallelStreamSupportTest { 68 | 69 | private Stream mappedDelegateMock; 70 | private IntStream mappedIntDelegateMock; 71 | private LongStream mappedLongDelegateMock; 72 | private DoubleStream mappedDoubleDelegateMock; 73 | private PrimitiveIterator.OfLong iteratorMock; 74 | private Spliterator.OfLong spliteratorMock; 75 | private long[] toArrayResult; 76 | private LongSummaryStatistics summaryStatistics; 77 | 78 | private ParallelLongStreamSupport parallelLongStreamSupport; 79 | 80 | @Override 81 | protected ParallelLongStreamSupport createParallelStreamSupportMock(ForkJoinPool workerPool) { 82 | return new ParallelLongStreamSupport(mock(LongStream.class), workerPool); 83 | } 84 | 85 | @BeforeEach 86 | @SuppressWarnings({"unchecked", "rawtypes"}) 87 | void init() { 88 | // Precondition for all tests 89 | assertFalse(currentThread() instanceof ForkJoinWorkerThread, "This test must not run in a ForkJoinPool"); 90 | 91 | this.mappedDelegateMock = mock(Stream.class); 92 | this.mappedIntDelegateMock = mock(IntStream.class); 93 | this.mappedLongDelegateMock = mock(LongStream.class); 94 | this.mappedDoubleDelegateMock = mock(DoubleStream.class); 95 | this.iteratorMock = mock(PrimitiveIterator.OfLong.class); 96 | this.spliteratorMock = mock(Spliterator.OfLong.class); 97 | this.toArrayResult = new long[0]; 98 | this.summaryStatistics = new LongSummaryStatistics(); 99 | 100 | when(this.delegateMock.map(any())).thenReturn(this.mappedLongDelegateMock); 101 | when(this.delegateMock.mapToObj(any())).thenReturn((Stream) this.mappedDelegateMock); 102 | when(this.delegateMock.mapToInt(any())).thenReturn(this.mappedIntDelegateMock); 103 | when(this.delegateMock.mapToDouble(any())).thenReturn(this.mappedDoubleDelegateMock); 104 | when(this.delegateMock.flatMap(any())).thenReturn(this.mappedLongDelegateMock); 105 | when(this.delegateMock.iterator()).thenReturn(this.iteratorMock); 106 | when(this.delegateMock.spliterator()).thenReturn(this.spliteratorMock); 107 | when(this.delegateMock.isParallel()).thenReturn(false); 108 | when(this.delegateMock.toArray()).thenReturn(this.toArrayResult); 109 | when(this.delegateMock.reduce(anyLong(), any())).thenReturn(42L); 110 | when(this.delegateMock.reduce(any())).thenReturn(OptionalLong.of(42)); 111 | when(this.delegateMock.collect(any(), any(), any())).thenReturn("collect"); 112 | when(this.delegateMock.sum()).thenReturn(42L); 113 | when(this.delegateMock.min()).thenReturn(OptionalLong.of(42)); 114 | when(this.delegateMock.max()).thenReturn(OptionalLong.of(42)); 115 | when(this.delegateMock.count()).thenReturn(42L); 116 | when(this.delegateMock.average()).thenReturn(OptionalDouble.of(42.0)); 117 | when(this.delegateMock.summaryStatistics()).thenReturn(this.summaryStatistics); 118 | when(this.delegateMock.anyMatch(any())).thenReturn(true); 119 | when(this.delegateMock.allMatch(any())).thenReturn(true); 120 | when(this.delegateMock.noneMatch(any())).thenReturn(true); 121 | when(this.delegateMock.findFirst()).thenReturn(OptionalLong.of(42)); 122 | when(this.delegateMock.findAny()).thenReturn(OptionalLong.of(42)); 123 | when(this.delegateMock.asDoubleStream()).thenReturn(this.mappedDoubleDelegateMock); 124 | when(this.delegateMock.boxed()).thenReturn((Stream) this.mappedDelegateMock); 125 | 126 | LongStream delegate = LongStream.of(1L).parallel(); 127 | this.parallelLongStreamSupport = new ParallelLongStreamSupport(delegate, this.workerPool); 128 | } 129 | 130 | @Test 131 | void parallelStreamWithArray() { 132 | LongStream stream = ParallelLongStreamSupport.parallelStream(new long[]{42}, this.workerPool); 133 | 134 | assertThat(stream, instanceOf(ParallelLongStreamSupport.class)); 135 | assertTrue(stream.isParallel()); 136 | assertEquals(OptionalLong.of(42), stream.findAny()); 137 | } 138 | 139 | @Test 140 | void parallelStreamWithNullArray() { 141 | assertThrows(NullPointerException.class, () -> ParallelLongStreamSupport.parallelStream((long[]) null, this.workerPool)); 142 | } 143 | 144 | @Test 145 | void parallelStreamSupportWithSpliterator() { 146 | Spliterator.OfLong spliterator = LongStream.of(42).spliterator(); 147 | LongStream stream = ParallelLongStreamSupport.parallelStream(spliterator, this.workerPool); 148 | 149 | assertThat(stream, instanceOf(ParallelLongStreamSupport.class)); 150 | assertTrue(stream.isParallel()); 151 | assertEquals(OptionalLong.of(42), stream.findAny()); 152 | } 153 | 154 | @Test 155 | void parallelStreamSupportWithNullSpliterator() { 156 | assertThrows(NullPointerException.class, () -> ParallelLongStreamSupport.parallelStream((Spliterator.OfLong) null, this.workerPool)); 157 | } 158 | 159 | @Test 160 | void parallelStreamSupportWithSpliteratorSupplier() { 161 | Supplier supplier = () -> LongStream.of(42).spliterator(); 162 | LongStream stream = ParallelLongStreamSupport.parallelStream(supplier, 0, this.workerPool); 163 | 164 | assertThat(stream, instanceOf(ParallelLongStreamSupport.class)); 165 | assertTrue(stream.isParallel()); 166 | assertEquals(OptionalLong.of(42), stream.findAny()); 167 | } 168 | 169 | @Test 170 | void parallelStreamSupportWithNullSpliteratorSupplier() { 171 | assertThrows(NullPointerException.class, () -> ParallelLongStreamSupport.parallelStream(null, 0, this.workerPool)); 172 | } 173 | 174 | @Test 175 | void parallelStreamWithBuilder() { 176 | Builder builder = LongStream.builder(); 177 | builder.accept(42); 178 | LongStream stream = ParallelLongStreamSupport.parallelStream(builder, this.workerPool); 179 | 180 | assertThat(stream, instanceOf(ParallelLongStreamSupport.class)); 181 | assertTrue(stream.isParallel()); 182 | assertEquals(OptionalLong.of(42), stream.findAny()); 183 | } 184 | 185 | @Test 186 | void parallelStreamWithNullBuilder() { 187 | assertThrows(NullPointerException.class, () -> ParallelLongStreamSupport.parallelStream((Builder) null, this.workerPool)); 188 | } 189 | 190 | @Test 191 | void iterate() { 192 | LongUnaryOperator operator = a -> a; 193 | LongStream stream = ParallelLongStreamSupport.iterate(42, operator, this.workerPool); 194 | 195 | assertThat(stream, instanceOf(ParallelLongStreamSupport.class)); 196 | assertTrue(stream.isParallel()); 197 | assertEquals(OptionalLong.of(42), stream.findAny()); 198 | } 199 | 200 | @Test 201 | void iterateWithNullOperator() { 202 | assertThrows(NullPointerException.class, () -> ParallelLongStreamSupport.iterate(42, null, this.workerPool)); 203 | } 204 | 205 | @Test 206 | void generate() { 207 | LongSupplier supplier = () -> 42; 208 | LongStream stream = ParallelLongStreamSupport.generate(supplier, this.workerPool); 209 | 210 | assertThat(stream, instanceOf(ParallelLongStreamSupport.class)); 211 | assertTrue(stream.isParallel()); 212 | assertEquals(OptionalLong.of(42), stream.findAny()); 213 | } 214 | 215 | @Test 216 | void generateWithNullSupplier() { 217 | assertThrows(NullPointerException.class, () -> ParallelLongStreamSupport.generate(null, this.workerPool)); 218 | } 219 | 220 | @Test 221 | void range() { 222 | LongStream stream = ParallelLongStreamSupport.range(0, 5, this.workerPool); 223 | 224 | assertThat(stream, instanceOf(ParallelLongStreamSupport.class)); 225 | assertTrue(stream.isParallel()); 226 | assertArrayEquals(stream.toArray(), new long[]{0, 1, 2, 3, 4}); 227 | } 228 | 229 | @Test 230 | void rangeClosed() { 231 | LongStream stream = ParallelLongStreamSupport.rangeClosed(0, 5, this.workerPool); 232 | 233 | assertThat(stream, instanceOf(ParallelLongStreamSupport.class)); 234 | assertTrue(stream.isParallel()); 235 | assertArrayEquals(stream.toArray(), new long[]{0, 1, 2, 3, 4, 5}); 236 | } 237 | 238 | @Test 239 | void concat() { 240 | LongStream a = LongStream.of(42); 241 | LongStream b = LongStream.of(43); 242 | LongStream stream = ParallelLongStreamSupport.concat(a, b, this.workerPool); 243 | 244 | assertThat(stream, instanceOf(ParallelLongStreamSupport.class)); 245 | assertTrue(stream.isParallel()); 246 | assertArrayEquals(stream.toArray(), new long[]{42, 43}); 247 | } 248 | 249 | @Test 250 | void concatWithNullStreamA() { 251 | assertThrows(NullPointerException.class, () -> ParallelLongStreamSupport.concat(null, LongStream.of(42), this.workerPool)); 252 | } 253 | 254 | @Test 255 | void concatWithNullStreamB() { 256 | assertThrows(NullPointerException.class, () -> ParallelLongStreamSupport.concat(LongStream.of(42), null, this.workerPool)); 257 | } 258 | 259 | @Test 260 | void filter() { 261 | LongPredicate p = i -> true; 262 | LongStream stream = this.parallelStreamSupportMock.filter(p); 263 | 264 | verify(this.delegateMock).filter(p); 265 | assertSame(this.parallelStreamSupportMock, stream); 266 | } 267 | 268 | @Test 269 | void map() { 270 | LongUnaryOperator f = i -> 42; 271 | LongStream stream = this.parallelStreamSupportMock.map(f); 272 | 273 | verify(this.delegateMock).map(f); 274 | assertThat(stream, instanceOf(ParallelLongStreamSupport.class)); 275 | assertSame(((ParallelLongStreamSupport) stream).delegate, this.mappedLongDelegateMock); 276 | assertSame(((ParallelLongStreamSupport) stream).workerPool, this.workerPool); 277 | } 278 | 279 | @Test 280 | void mapToObj() { 281 | LongFunction f = i -> "x"; 282 | Stream stream = this.parallelStreamSupportMock.mapToObj(f); 283 | 284 | verify(this.delegateMock).mapToObj(f); 285 | assertThat(stream, instanceOf(ParallelStreamSupport.class)); 286 | assertSame(((ParallelStreamSupport) stream).delegate, this.mappedDelegateMock); 287 | assertSame(((ParallelStreamSupport) stream).workerPool, this.workerPool); 288 | } 289 | 290 | @Test 291 | void mapToInt() { 292 | LongToIntFunction f = i -> 1; 293 | IntStream stream = this.parallelStreamSupportMock.mapToInt(f); 294 | 295 | verify(this.delegateMock).mapToInt(f); 296 | assertThat(stream, instanceOf(ParallelIntStreamSupport.class)); 297 | assertSame(((ParallelIntStreamSupport) stream).delegate, this.mappedIntDelegateMock); 298 | assertSame(((ParallelIntStreamSupport) stream).workerPool, this.workerPool); 299 | } 300 | 301 | @Test 302 | void mapToDouble() { 303 | LongToDoubleFunction f = i -> 1.0; 304 | DoubleStream stream = this.parallelStreamSupportMock.mapToDouble(f); 305 | 306 | verify(this.delegateMock).mapToDouble(f); 307 | assertThat(stream, instanceOf(ParallelDoubleStreamSupport.class)); 308 | assertSame(((ParallelDoubleStreamSupport) stream).delegate, this.mappedDoubleDelegateMock); 309 | assertSame(((ParallelDoubleStreamSupport) stream).workerPool, this.workerPool); 310 | } 311 | 312 | @Test 313 | void flatMap() { 314 | LongFunction f = i -> LongStream.of(1); 315 | LongStream stream = this.parallelStreamSupportMock.flatMap(f); 316 | 317 | verify(this.delegateMock).flatMap(f); 318 | assertThat(stream, instanceOf(ParallelLongStreamSupport.class)); 319 | assertSame(((ParallelLongStreamSupport) stream).delegate, this.mappedLongDelegateMock); 320 | } 321 | 322 | @Test 323 | void distinct() { 324 | LongStream stream = this.parallelStreamSupportMock.distinct(); 325 | 326 | verify(this.delegateMock).distinct(); 327 | assertSame(this.parallelStreamSupportMock, stream); 328 | } 329 | 330 | @Test 331 | void sorted() { 332 | LongStream stream = this.parallelStreamSupportMock.sorted(); 333 | 334 | verify(this.delegateMock).sorted(); 335 | assertSame(this.parallelStreamSupportMock, stream); 336 | } 337 | 338 | @Test 339 | void peek() { 340 | LongConsumer c = i -> { 341 | }; 342 | LongStream stream = this.parallelStreamSupportMock.peek(c); 343 | 344 | verify(this.delegateMock).peek(c); 345 | assertSame(this.parallelStreamSupportMock, stream); 346 | } 347 | 348 | @Test 349 | void limit() { 350 | LongStream stream = this.parallelStreamSupportMock.limit(5); 351 | 352 | verify(this.delegateMock).limit(5); 353 | assertSame(this.parallelStreamSupportMock, stream); 354 | } 355 | 356 | @Test 357 | void skip() { 358 | LongStream stream = this.parallelStreamSupportMock.skip(5); 359 | 360 | verify(this.delegateMock).skip(5); 361 | assertSame(this.parallelStreamSupportMock, stream); 362 | } 363 | 364 | @Test 365 | void takeWhile() { 366 | LongPredicate predicate = x -> true; 367 | LongStream stream = this.parallelStreamSupportMock.takeWhile(predicate); 368 | 369 | verify(this.delegateMock).takeWhile(predicate); 370 | assertSame(this.parallelStreamSupportMock, stream); 371 | } 372 | 373 | @Test 374 | void dropWhile() { 375 | LongPredicate predicate = x -> true; 376 | LongStream stream = this.parallelStreamSupportMock.dropWhile(predicate); 377 | 378 | verify(this.delegateMock).dropWhile(predicate); 379 | assertSame(this.parallelStreamSupportMock, stream); 380 | } 381 | 382 | @Test 383 | void forEach() { 384 | LongConsumer c = i -> { 385 | }; 386 | this.parallelStreamSupportMock.forEach(c); 387 | 388 | verify(this.delegateMock).forEach(c); 389 | } 390 | 391 | @Test 392 | void forEachSequential() { 393 | this.parallelLongStreamSupport.sequential(); 394 | Thread thisThread = currentThread(); 395 | AtomicReference threadRef = new AtomicReference<>(); 396 | 397 | this.parallelLongStreamSupport.forEach(i -> threadRef.set(currentThread())); 398 | 399 | assertEquals(thisThread, threadRef.get()); 400 | } 401 | 402 | @Test 403 | void forEachParallel() { 404 | this.parallelLongStreamSupport.parallel(); 405 | AtomicReference threadRef = new AtomicReference<>(); 406 | 407 | this.parallelLongStreamSupport.forEach(i -> threadRef.set(currentThread())); 408 | 409 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 410 | } 411 | 412 | @Test 413 | void forEachOrdered() { 414 | LongConsumer c = i -> { 415 | }; 416 | this.parallelStreamSupportMock.forEachOrdered(c); 417 | 418 | verify(this.delegateMock).forEachOrdered(c); 419 | } 420 | 421 | @Test 422 | void forEachOrderedSequential() { 423 | this.parallelLongStreamSupport.sequential(); 424 | Thread thisThread = currentThread(); 425 | AtomicReference threadRef = new AtomicReference<>(); 426 | 427 | this.parallelLongStreamSupport.forEachOrdered(i -> threadRef.set(currentThread())); 428 | 429 | assertEquals(thisThread, threadRef.get()); 430 | } 431 | 432 | @Test 433 | void forEachOrderedParallel() { 434 | this.parallelLongStreamSupport.parallel(); 435 | AtomicReference threadRef = new AtomicReference<>(); 436 | 437 | this.parallelLongStreamSupport.forEachOrdered(i -> threadRef.set(currentThread())); 438 | 439 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 440 | } 441 | 442 | @Test 443 | void toArray() { 444 | long[] array = this.parallelStreamSupportMock.toArray(); 445 | 446 | verify(this.delegateMock).toArray(); 447 | assertSame(this.toArrayResult, array); 448 | } 449 | 450 | @Test 451 | void toArraySequential() { 452 | this.parallelLongStreamSupport.sequential(); 453 | Thread thisThread = currentThread(); 454 | AtomicReference threadRef = new AtomicReference<>(); 455 | 456 | this.parallelLongStreamSupport 457 | .peek(i -> threadRef.set(currentThread())) 458 | .toArray(); 459 | 460 | assertEquals(thisThread, threadRef.get()); 461 | } 462 | 463 | @Test 464 | void toArrayParallel() { 465 | this.parallelLongStreamSupport.parallel(); 466 | AtomicReference threadRef = new AtomicReference<>(); 467 | 468 | this.parallelLongStreamSupport 469 | .peek(i -> threadRef.set(currentThread())) 470 | .toArray(); 471 | 472 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 473 | } 474 | 475 | @Test 476 | void reduceWithIdentityAndAccumulator() { 477 | LongBinaryOperator accumulator = (a, b) -> b; 478 | long result = this.parallelStreamSupportMock.reduce(0, accumulator); 479 | 480 | verify(this.delegateMock).reduce(0, accumulator); 481 | assertEquals(42, result); 482 | } 483 | 484 | @Test 485 | void reduceWithIdentityAndAccumulatorSequential() { 486 | this.parallelLongStreamSupport.sequential(); 487 | LongBinaryOperator accumulator = (a, b) -> b; 488 | Thread thisThread = currentThread(); 489 | AtomicReference threadRef = new AtomicReference<>(); 490 | 491 | this.parallelLongStreamSupport 492 | .peek(i -> threadRef.set(currentThread())) 493 | .reduce(0, accumulator); 494 | 495 | assertEquals(thisThread, threadRef.get()); 496 | } 497 | 498 | @Test 499 | void reduceWithIdentityAndAccumulatorParallel() { 500 | this.parallelLongStreamSupport.parallel(); 501 | LongBinaryOperator accumulator = (a, b) -> b; 502 | AtomicReference threadRef = new AtomicReference<>(); 503 | 504 | this.parallelLongStreamSupport 505 | .peek(i -> threadRef.set(currentThread())) 506 | .reduce(0, accumulator); 507 | 508 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 509 | } 510 | 511 | @Test 512 | void reduceWithAccumulator() { 513 | LongBinaryOperator accumulator = (a, b) -> b; 514 | OptionalLong result = this.parallelStreamSupportMock.reduce(accumulator); 515 | 516 | verify(this.delegateMock).reduce(accumulator); 517 | assertEquals(OptionalLong.of(42), result); 518 | } 519 | 520 | @Test 521 | void reduceWithAccumulatorSequential() { 522 | this.parallelLongStreamSupport.sequential(); 523 | LongBinaryOperator accumulator = (a, b) -> b; 524 | Thread thisThread = currentThread(); 525 | AtomicReference threadRef = new AtomicReference<>(); 526 | 527 | this.parallelLongStreamSupport 528 | .peek(i -> threadRef.set(currentThread())) 529 | .reduce(accumulator); 530 | 531 | assertEquals(thisThread, threadRef.get()); 532 | } 533 | 534 | @Test 535 | void reduceWithAccumulatorParallel() { 536 | this.parallelLongStreamSupport.parallel(); 537 | LongBinaryOperator accumulator = (a, b) -> b; 538 | AtomicReference threadRef = new AtomicReference<>(); 539 | 540 | this.parallelLongStreamSupport 541 | .peek(i -> threadRef.set(currentThread())) 542 | .reduce(accumulator); 543 | 544 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 545 | } 546 | 547 | @Test 548 | void collectWithSupplierAndAccumulatorAndCombiner() { 549 | Supplier supplier = () -> "x"; 550 | ObjLongConsumer accumulator = (a, b) -> { 551 | }; 552 | BiConsumer combiner = (a, b) -> { 553 | }; 554 | 555 | String result = this.parallelStreamSupportMock.collect(supplier, accumulator, combiner); 556 | 557 | verify(this.delegateMock).collect(supplier, accumulator, combiner); 558 | assertEquals("collect", result); 559 | } 560 | 561 | @Test 562 | void collectWithSupplierAndAccumulatorAndCombinerSequential() { 563 | this.parallelLongStreamSupport.sequential(); 564 | Thread thisThread = currentThread(); 565 | AtomicReference threadRef = new AtomicReference<>(); 566 | 567 | this.parallelLongStreamSupport 568 | .peek(i -> threadRef.set(currentThread())) 569 | .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); 570 | 571 | assertEquals(thisThread, threadRef.get()); 572 | } 573 | 574 | @Test 575 | void collectWithSupplierAndAccumulatorAndCombinerParallel() { 576 | this.parallelLongStreamSupport.parallel(); 577 | AtomicReference threadRef = new AtomicReference<>(); 578 | 579 | this.parallelLongStreamSupport 580 | .peek(i -> threadRef.set(currentThread())) 581 | .collect(ArrayList::new, ArrayList::add, ArrayList::addAll); 582 | 583 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 584 | } 585 | 586 | @Test 587 | void sum() { 588 | long result = this.parallelStreamSupportMock.sum(); 589 | 590 | verify(this.delegateMock).sum(); 591 | assertEquals(42, result); 592 | } 593 | 594 | @Test 595 | void sumSequential() { 596 | this.parallelLongStreamSupport.sequential(); 597 | Thread thisThread = currentThread(); 598 | AtomicReference threadRef = new AtomicReference<>(); 599 | 600 | this.parallelLongStreamSupport 601 | .peek(i -> threadRef.set(currentThread())) 602 | .sum(); 603 | 604 | assertEquals(thisThread, threadRef.get()); 605 | } 606 | 607 | @Test 608 | void sumParallel() { 609 | this.parallelLongStreamSupport.parallel(); 610 | AtomicReference threadRef = new AtomicReference<>(); 611 | 612 | this.parallelLongStreamSupport 613 | .peek(i -> threadRef.set(currentThread())) 614 | .sum(); 615 | 616 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 617 | } 618 | 619 | @Test 620 | void min() { 621 | OptionalLong result = this.parallelStreamSupportMock.min(); 622 | 623 | verify(this.delegateMock).min(); 624 | assertEquals(OptionalLong.of(42), result); 625 | } 626 | 627 | @Test 628 | void minSequential() { 629 | this.parallelLongStreamSupport.sequential(); 630 | Thread thisThread = currentThread(); 631 | AtomicReference threadRef = new AtomicReference<>(); 632 | 633 | this.parallelLongStreamSupport 634 | .peek(i -> threadRef.set(currentThread())) 635 | .min(); 636 | 637 | assertEquals(thisThread, threadRef.get()); 638 | } 639 | 640 | @Test 641 | void minParallel() { 642 | this.parallelLongStreamSupport.parallel(); 643 | AtomicReference threadRef = new AtomicReference<>(); 644 | 645 | this.parallelLongStreamSupport 646 | .peek(i -> threadRef.set(currentThread())) 647 | .min(); 648 | 649 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 650 | } 651 | 652 | @Test 653 | void max() { 654 | OptionalLong result = this.parallelStreamSupportMock.max(); 655 | 656 | verify(this.delegateMock).max(); 657 | assertEquals(OptionalLong.of(42), result); 658 | } 659 | 660 | @Test 661 | void maxSequential() { 662 | this.parallelLongStreamSupport.sequential(); 663 | Thread thisThread = currentThread(); 664 | AtomicReference threadRef = new AtomicReference<>(); 665 | 666 | this.parallelLongStreamSupport 667 | .peek(i -> threadRef.set(currentThread())) 668 | .max(); 669 | 670 | assertEquals(thisThread, threadRef.get()); 671 | } 672 | 673 | @Test 674 | void maxParallel() { 675 | this.parallelLongStreamSupport.parallel(); 676 | AtomicReference threadRef = new AtomicReference<>(); 677 | 678 | this.parallelLongStreamSupport 679 | .peek(i -> threadRef.set(currentThread())) 680 | .max(); 681 | 682 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 683 | } 684 | 685 | @Test 686 | void count() { 687 | long count = this.parallelStreamSupportMock.count(); 688 | 689 | verify(this.delegateMock).count(); 690 | assertEquals(42, count); 691 | } 692 | 693 | @Test 694 | void countSequential() { 695 | this.parallelLongStreamSupport.sequential(); 696 | Thread thisThread = currentThread(); 697 | AtomicReference threadRef = new AtomicReference<>(); 698 | 699 | this.parallelLongStreamSupport 700 | // Don't use peek() in combination with count(). See Javadoc. 701 | .filter(i -> { 702 | threadRef.set(currentThread()); 703 | return true; 704 | }).count(); 705 | 706 | assertEquals(thisThread, threadRef.get()); 707 | } 708 | 709 | @Test 710 | void countParallel() { 711 | this.parallelLongStreamSupport.parallel(); 712 | AtomicReference threadRef = new AtomicReference<>(); 713 | 714 | this.parallelLongStreamSupport 715 | // Don't use peek() in combination with count(). See Javadoc. 716 | .filter(i -> { 717 | threadRef.set(currentThread()); 718 | return true; 719 | }).count(); 720 | 721 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 722 | } 723 | 724 | @Test 725 | void average() { 726 | OptionalDouble result = this.parallelStreamSupportMock.average(); 727 | 728 | verify(this.delegateMock).average(); 729 | assertEquals(OptionalDouble.of(42.0), result); 730 | } 731 | 732 | @Test 733 | void averageSequential() { 734 | this.parallelLongStreamSupport.sequential(); 735 | Thread thisThread = currentThread(); 736 | AtomicReference threadRef = new AtomicReference<>(); 737 | 738 | this.parallelLongStreamSupport 739 | .peek(i -> threadRef.set(currentThread())) 740 | .average(); 741 | 742 | assertEquals(thisThread, threadRef.get()); 743 | } 744 | 745 | @Test 746 | void averageParallel() { 747 | this.parallelLongStreamSupport.parallel(); 748 | AtomicReference threadRef = new AtomicReference<>(); 749 | 750 | this.parallelLongStreamSupport 751 | .peek(i -> threadRef.set(currentThread())) 752 | .average(); 753 | 754 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 755 | } 756 | 757 | @Test 758 | void summaryStatistics() { 759 | LongSummaryStatistics result = this.parallelStreamSupportMock.summaryStatistics(); 760 | 761 | verify(this.delegateMock).summaryStatistics(); 762 | assertEquals(this.summaryStatistics, result); 763 | } 764 | 765 | @Test 766 | void summaryStatisticsSequential() { 767 | this.parallelLongStreamSupport.sequential(); 768 | Thread thisThread = currentThread(); 769 | AtomicReference threadRef = new AtomicReference<>(); 770 | 771 | this.parallelLongStreamSupport 772 | .peek(i -> threadRef.set(currentThread())) 773 | .summaryStatistics(); 774 | 775 | assertEquals(thisThread, threadRef.get()); 776 | } 777 | 778 | @Test 779 | void summaryStatisticsParallel() { 780 | this.parallelLongStreamSupport.parallel(); 781 | AtomicReference threadRef = new AtomicReference<>(); 782 | 783 | this.parallelLongStreamSupport 784 | .peek(i -> threadRef.set(currentThread())) 785 | .summaryStatistics(); 786 | 787 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 788 | } 789 | 790 | @Test 791 | void anyMatch() { 792 | LongPredicate p = i -> true; 793 | 794 | boolean result = this.parallelStreamSupportMock.anyMatch(p); 795 | 796 | verify(this.delegateMock).anyMatch(p); 797 | assertTrue(result); 798 | } 799 | 800 | @Test 801 | void anyMatchSequential() { 802 | this.parallelLongStreamSupport.sequential(); 803 | Thread thisThread = currentThread(); 804 | AtomicReference threadRef = new AtomicReference<>(); 805 | 806 | this.parallelLongStreamSupport 807 | .peek(i -> threadRef.set(currentThread())) 808 | .anyMatch(i -> true); 809 | 810 | assertEquals(thisThread, threadRef.get()); 811 | } 812 | 813 | @Test 814 | void anyMatchParallel() { 815 | this.parallelLongStreamSupport.parallel(); 816 | AtomicReference threadRef = new AtomicReference<>(); 817 | 818 | this.parallelLongStreamSupport 819 | .peek(i -> threadRef.set(currentThread())) 820 | .anyMatch(i -> true); 821 | 822 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 823 | } 824 | 825 | @Test 826 | void allMatch() { 827 | LongPredicate p = i -> true; 828 | 829 | boolean result = this.parallelStreamSupportMock.allMatch(p); 830 | 831 | verify(this.delegateMock).allMatch(p); 832 | assertTrue(result); 833 | } 834 | 835 | @Test 836 | void allMatchSequential() { 837 | this.parallelLongStreamSupport.sequential(); 838 | Thread thisThread = currentThread(); 839 | AtomicReference threadRef = new AtomicReference<>(); 840 | 841 | this.parallelLongStreamSupport 842 | .peek(i -> threadRef.set(currentThread())) 843 | .allMatch(i -> true); 844 | 845 | assertEquals(thisThread, threadRef.get()); 846 | } 847 | 848 | @Test 849 | void allMatchParallel() { 850 | this.parallelLongStreamSupport.parallel(); 851 | AtomicReference threadRef = new AtomicReference<>(); 852 | 853 | this.parallelLongStreamSupport 854 | .peek(i -> threadRef.set(currentThread())) 855 | .allMatch(i -> true); 856 | 857 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 858 | } 859 | 860 | @Test 861 | void noneMatch() { 862 | LongPredicate p = i -> true; 863 | 864 | boolean result = this.parallelStreamSupportMock.noneMatch(p); 865 | 866 | verify(this.delegateMock).noneMatch(p); 867 | assertTrue(result); 868 | } 869 | 870 | @Test 871 | void noneMatchSequential() { 872 | this.parallelLongStreamSupport.sequential(); 873 | Thread thisThread = currentThread(); 874 | AtomicReference threadRef = new AtomicReference<>(); 875 | 876 | this.parallelLongStreamSupport 877 | .peek(i -> threadRef.set(currentThread())) 878 | .noneMatch(i -> true); 879 | 880 | assertEquals(thisThread, threadRef.get()); 881 | } 882 | 883 | @Test 884 | void noneMatchParallel() { 885 | this.parallelLongStreamSupport.parallel(); 886 | AtomicReference threadRef = new AtomicReference<>(); 887 | 888 | this.parallelLongStreamSupport 889 | .peek(i -> threadRef.set(currentThread())) 890 | .noneMatch(i -> true); 891 | 892 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 893 | } 894 | 895 | @Test 896 | void findFirst() { 897 | OptionalLong result = this.parallelStreamSupportMock.findFirst(); 898 | 899 | verify(this.delegateMock).findFirst(); 900 | assertEquals(OptionalLong.of(42), result); 901 | } 902 | 903 | @Test 904 | void findFirstSequential() { 905 | this.parallelLongStreamSupport.sequential(); 906 | Thread thisThread = currentThread(); 907 | AtomicReference threadRef = new AtomicReference<>(); 908 | 909 | this.parallelLongStreamSupport 910 | .peek(i -> threadRef.set(currentThread())) 911 | .findFirst(); 912 | 913 | assertEquals(thisThread, threadRef.get()); 914 | } 915 | 916 | @Test 917 | void findFirstParallel() { 918 | this.parallelLongStreamSupport.parallel(); 919 | AtomicReference threadRef = new AtomicReference<>(); 920 | 921 | this.parallelLongStreamSupport 922 | .peek(i -> threadRef.set(currentThread())) 923 | .findFirst(); 924 | 925 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 926 | } 927 | 928 | @Test 929 | void findAny() { 930 | OptionalLong result = this.parallelStreamSupportMock.findAny(); 931 | 932 | verify(this.delegateMock).findAny(); 933 | assertEquals(OptionalLong.of(42), result); 934 | } 935 | 936 | @Test 937 | void findAnytSequential() { 938 | this.parallelLongStreamSupport.sequential(); 939 | Thread thisThread = currentThread(); 940 | AtomicReference threadRef = new AtomicReference<>(); 941 | 942 | this.parallelLongStreamSupport 943 | .peek(i -> threadRef.set(currentThread())) 944 | .findAny(); 945 | 946 | assertEquals(thisThread, threadRef.get()); 947 | } 948 | 949 | @Test 950 | void findAnyParallel() { 951 | this.parallelLongStreamSupport.parallel(); 952 | AtomicReference threadRef = new AtomicReference<>(); 953 | 954 | this.parallelLongStreamSupport 955 | .peek(i -> threadRef.set(currentThread())) 956 | .findAny(); 957 | 958 | assertThat(threadRef.get(), instanceOf(ForkJoinWorkerThread.class)); 959 | } 960 | 961 | @Test 962 | void asDoubleStream() { 963 | DoubleStream stream = this.parallelStreamSupportMock.asDoubleStream(); 964 | 965 | verify(this.delegateMock).asDoubleStream(); 966 | assertThat(stream, instanceOf(ParallelDoubleStreamSupport.class)); 967 | assertSame(this.mappedDoubleDelegateMock, ((ParallelDoubleStreamSupport) stream).delegate); 968 | assertSame(this.workerPool, ((ParallelDoubleStreamSupport) stream).workerPool); 969 | } 970 | 971 | @Test 972 | void boxed() { 973 | Stream stream = this.parallelStreamSupportMock.boxed(); 974 | 975 | verify(this.delegateMock).boxed(); 976 | assertThat(stream, instanceOf(ParallelStreamSupport.class)); 977 | assertSame(this.mappedDelegateMock, ((ParallelStreamSupport) stream).delegate); 978 | assertSame(this.workerPool, ((ParallelStreamSupport) stream).workerPool); 979 | } 980 | 981 | @Override 982 | @Test 983 | void iterator() { 984 | PrimitiveIterator.OfLong iterator = this.parallelStreamSupportMock.iterator(); 985 | 986 | verify(this.delegateMock).iterator(); 987 | assertSame(this.iteratorMock, iterator); 988 | } 989 | 990 | @Override 991 | @Test 992 | void spliterator() { 993 | Spliterator.OfLong spliterator = this.parallelStreamSupportMock.spliterator(); 994 | 995 | verify(this.delegateMock).spliterator(); 996 | assertSame(this.spliteratorMock, spliterator); 997 | } 998 | } 999 | --------------------------------------------------------------------------------