CHAP07 - Modern-Java-in-Action/Online-Study GitHub Wiki
- ์ด ์ฅ์์๋
- ๋ณ๋ ฌ ์คํธ๋ฆผ์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณ๋ ฌ ์ฒ๋ฆฌํ๊ธฐ
- ๋ณ๋ ฌ ์คํธ๋ฆผ์ ์ฑ๋ฅ ๋ถ์
- ํฌํฌ/์กฐ์ธ ํ๋ ์์ํฌ
- Spliterator๋ก ์คํธ๋ฆผ ๋ฐ์ดํฐ ์ชผ๊ฐ๊ธฐ
- parallelStream(): ์คํธ๋ฆผ ์์๋ฅผ ์ฒญํฌ๋ก ๋ถํ ๋ ๋ณ๋ ฌ ์คํธ๋ฆผ ์์ฑ๋๋ค.
- ์ฌ๋ก: n๊น์ง์ ์ซ์ ํฉ๊ณ
- ๋ฌดํ ์คํธ๋ฆผ ์์ฑ
- n์ผ๋ก ์คํธ๋ฆผ ํฌ๊ธฐ ์ ํ
- ๋ํ๋ ๋ฆฌ๋์ฑ ์์ ์
public long sequentialSum(long n) {
return Stream.iterate(1L, i -> i + 1)
.limit(n)
.reduce(0L, Long::sum);
}- ์ ํต์ ์ธ ๋ฐฉ์
public long iterativeSum(long n) {
long result = 0;
for (long i = 1L; i <= n; i++) {
result += i;
}
return result;
}- ์ด๋ฐ ๊ฑฑ์ NO
- ๊ฒฐ๊ณผ ๋ณ์๋ฅผ ์ด๋ป๊ฒ ๋๊ธฐํํด์ผ?
- ๋ช๊ฐ์ ์ค๋ ๋๋ฅผ ์ฌ์ฉํด์ผ?
- ์ซ์๋ ์ด๋ป๊ฒ ์์ฑ?
- ์์ฑ๋ ์ซ์๋ ๋๊ฐ ๋ํ ๊น?
- parallel() ๋ฉ์๋ ์ถ๊ฐ
- ์ฌ๋ฌ ์ฒญํฌ๋ก ๋ถํ
public long parallelSum(long n) {
return Stream.iterate(1L, i -> i + 1)
.limit(n)
.parallel()
.reduce(0L, Long::sum);
}- sequential() ๋ ์๋ค.
- ๋ฒ๊ฐ์ ์ฌ์ฉํ ๊ฒฝ์ฐ, ๋ง์ง๋ง ํธ์ถ์ด ์ ์ฒด ํ์ดํ๋ผ์ธ์ ์ํฅ์ ๋ฏธ์น๋ค.
- pararellel์ด ๋ง์ง๋ง ํธ์ถ๋ฌ์ผ๋.
stream.parallel()
.filter(...)
.sequential()
.map(...)
.parallel()
.reduce();- 3๊ฐ์ง ๊ธฐ๋ฒ ์ฑ๋ฅ ๋น๊ต
- ๋ฐ๋ณตํ, ์์ฐจ๋ฆฌ๋์คํ, ๋ณ๋ ฌ ๋ฆฌ๋์ฑ
- ๋๊ตฌ: JMH (Java Microbenchmark Harness)
- ์ด๋ ธํ ์ด์ ๋ฐฉ์์ผ๋ก ์ธก์ ์ฌํ
- ์ค์
- XML ์ค์
- ์ด๋ ธํ ์ด์ ์ถ๊ฐ
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.17.4</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.17.4</version>
</dependency><build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
<configuration>
<finalName>benchmarks</finalName>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.
resource.ManifestResourceTransformer">
<mainClass>org.openjdk.jmh.Main</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>@BenchmarkMode(Mode.AverageTime) // ํ๊ท ์๊ฐ ์ธก์
@OutputTimeUnit(TimeUnit.MILLISECONDS) // ๋ฐ๋ฆฌ์ด ๋จ์ ์ถ๋ ฅ
@Fork(2, jvmArgs={"-Xms4G", "-Xmx4G"}) // 2๋ฒ ์คํ (์ ๋ขฐ์ฑ UP)
public class ParallelStreamBenchmark {
private static final long N= 10_000_000L;
@Benchmark // ๋ฒค์น๋งํฌ ๋์ ๋ฉ์๋
public long sequentialSum() {
return Stream.iterate(1L, i -> i + 1).limit(N)
.reduce( 0L, Long::sum);
}
@TearDown(Level.Invocation) // ๊ฐ ๋ฒค์น๋งํฌ ๋ณ ๊ฐ๋น์ง ์ปฌ๋ ํฐ ๋์ ์ํค๊ธฐ
public void tearDown() {
System.gc();
}
}- ์คํ ํ๊ฒฝ
- i7-4600u 2.1GHz ์ฟผ๋ ์ฝ์ด
๊ธฐ์กด ๋ฐ๋ณตํ (iterativeSum)
- ์๊ฐ: 3.278 ms
for (long i = 1L; i <= n; i++) {
result += i;
}์์ฐจ๋ฆฌ๋์คํ (sequentialSum)
- ์๊ฐ: 121.843 ms
Stream.iterate(1L, i -> i + 1)
.limit(n)
.reduce(0L, Long::sum);๋ณ๋ ฌ ๋ฆฌ๋์ฑ (parallelSum)
- ์๊ฐ: 604.059 ms
Stream.iterate(1L, i -> i + 1)
.limit(n)
.parallel()
.reduce(0L, Long::sum);๊ฒฐ๊ณผ๋ฅผ ๋ณด๋ฉด,
- for๋ฌธ์ด ๊ฐ์ฅ ๋น ๋ฅด๊ฒ ๋์๋ค.
- ์์ธ์ ๊ฒฐ๊ณผ๊ฐ ๋์จ ์ด์
- ๋ฐ์ฑ๋ ๊ฐ์ฒด๊ฐ ๋ง๋ค์ด์ง๋ฏ๋ก, ๋ํ๋ ค๋ฉด ์ธ๋ฐ์ฑ์ ํด์ผํ๋ค.
- ๋ฐ๋ณต ์์ ์ ๋ณ๋ ฌ๋ก ์ํํ ์ ์๋ ๋ ๋ฆฝ ๋จ์๋ก ๋๋๊ธฐ๊ฐ ์ด๋ ต๋ค.
- ์ด์ฒ๋ผ ๋ณ๋ ฌ ํ๋ก๊ทธ๋๋ฐ์ ํจ์ ์ด ์จ์ด์๋ค.
- LongStream.rangeClosed() ์ฅ์
- ๊ธฐ๋ณธํ long์ ์ง์ ์ฌ์ฉํ๋ฏ๋ก, ๋ฐ์ฑ๊ณผ ์ธ๋ฐ์ฑ ์ค๋ฒํค๋ x
- ์ฝ๊ฒ ์ฒญํฌ๋ก ๋ถํ ํ ์ ์๋ ์ซ์ ๋ฒ์๋ฅผ ์์ฑ ํด์ค๋ค.
- ์, 1~20์ 1-5, 6-10, 11-15, 16-20 ๋ก ๋ถํ
- ์๋ ์ฝ๋ ๊ฑธ๋ฆฐ ์๊ฐ: 5.315 ms
- ๊ธฐ์กด iterate ๋ฉ์๋ ๋ณด๋ค ์๋๊ฐ ๋น ๋ฅด๋ค.
- ์ด๋ค ์๊ณ ๋ฆฌ์ฆ ๋ณ๋ ฌํ๋ฅผ ์ ํํ๋ ๊ฒ๋ณด๋ค ์ ์ ํ ์๋ฃ๊ตฌ์กฐ ์ ํ์ด ์ค์ํ๋ค.
@Benchmark
public long rangedSum() {
return LongStream.rangeClosed(1, N)
.reduce(0L, Long::sum);
}- ํ์ง๋ง, ๋ณ๋ ฌ ์คํธ๋ฆผ์ ์ ์ฉํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
- ์๋ ์ฝ๋ ๊ฑธ๋ฆฐ ์๊ฐ: 2.677 ms
- ๋๋์ด ๋น ๋ฅธ ๋ณ๋ ฌ ๋ฆฌ๋์ฑ์ ๋ง๋ค์๋ค.
@Benchmark
public long parallelRangedSum() {
return LongStream.rangeClosed(1, N)
.parallel()
.reduce(0L, Long::sum);
}์ฃผ์ํ ์
- ์๋ธ์คํธ๋ฆผ์ ์๋ก ๋ค๋ฅธ ์ค๋ ๋์ ๋ฆฌ๋์ฑ ์ฐ์ฐ์ ํ ๋นํ๊ณ ๋ค์ ํฉ์น๋๋ฐ, ์ฆ, ๋ฉํฐ์ฝ์ด๊ฐ ๋ฐ์ดํฐ ์ด๋์ ๋น์ธ๋ค. ์ด๋ถ๋ถ์ ์ฃผ์ํด์ผ ํ๋ค.
- ํด์ฆ: ๋ค์ ์ฝ๋์ ๋ฌธ์ ๋ ๋ฌด์์ผ๊น?
- ๋ต: total์ด ๊ณต์ ๋ ์ํ์ด๊ธฐ์ ๋ฐ์ดํฐ ๋ ์ด์ค๊ฐ ๋ฐ์ ํ ์ ์์ด, ์๋ ์ฝ๋๋ ๋ณ๋ ฌ ์คํธ๋ฆผ์ ์ฌ์ฉํ ์ ์๋ ์ฝ๋์ด๋ค.
public long sideEffectSum(long n) {
Accumulator accumulator = new Accumulator();
LongStream.rangeClosed(1, n).parallel().forEach(accumulator::add);
return accumulator.total;
}
public class Accumulator {
public long total = 0;
public void add(long value) { total += value; }
}System.out.println(sideEffectSum(10_000_000L)); // ์ฝ๋ ์คํ์ ๊ฒฐ๊ณผ 500000500000์ด ๋์ค์ง ์๋๋ค...- 1000๊ฐ ์ด์ ์์์ผ ๋ ๋ณ๋ ฌ ์คํธ๋ฆผ ์ฌ์ฉ -> ์ด๋ฐ ๊ธฐ์ค์ ์๋ค
- ๊ทธ๋ฌ๋, ์๋์ ํํธ ์ฌ์ฉ์ ๋์
- ๋ฒค์น๋งํฌ๋ก ์ง์ ์ธก์
- ๋ฐ์ฑ ์ฃผ์
- IntStream, LongStream, DoubleStream ์ฌ์ฉ ์ถ์ฒ
- ์์ฐจ ์คํธ๋ฆผ๋ณด๋ค ๋ณ๋ ฌ ์คํธ๋ฆผ์์ ์ฑ๋ฅ์ด ๋จ์ด์ง๋ ์ฐ์ฐ
- ์: limit(), findFirst()
- ํ์ดํ๋ผ์ธ ์ฐ์ฐ ๋น์ฉ ๊ณ ๋ ค
- N*Q
- N: ์ฒ๋ฆฌํ ์์์
- Q: ํ๋ ์์ ์ฒ๋ฆฌ์ ๋๋ ๋น์ฉ
- Q๊ฐ ๋์ ๊ฒฝ์ฐ, ๋ณ๋ ฌ ์คํธ๋ฆผ ์ฌ์ฉ์ ๊ฐ์ ๋ ํ๋ฅ ์ด ๋๋ค.
- N*Q
- ์๋ ๋ฐ์ดํฐ์์ ๋ณ๋ ฌ ์คํธ๋ฆผ์ ๋์ x
- ์๋ฃ๊ตฌ์กฐ๊ฐ ์ ์ ํ์ง ํ์ธ
- LinkedList ๋ณด๋จ ArrayList๊ฐ ํจ์จ์ ์ผ๋ก ๋ถํ ๊ฐ๋ฅ. ์? LL์ ๋ชจ๋ ์์ ํ์ํด์ผ ํ๋.
- ์คํธ๋ฆผ์ ํน์ฑ๊ณผ ํ์ดํ๋ผ์ธ์ ์ค๊ฐ์ฐ์ฐ์ด ์คํธ๋ฆผ์ ํน์ฑ์ ์ด๋ป๊ฒ ๋ฐ๊พธ๋์ง์ ๋ฐ๋ผ ๋ถํด ๊ณผ์ ์ฑ๋ฅ์ด ๋ฌ๋ผ์ง ์ ์๋ค.
- ์ฝ๊ฒ ๋งํด, SIZED ์คํธ๋ฆผ์ ๊ฐ์ ํฌ๊ธฐ๋ก ๋ถํ ๊ฐ๋ฅํ๋ฐ, ํํฐ์ฐ์ฐ์ด ์์ผ๋ฉด ์คํธ๋ฆผ ๊ธธ์ด๋ฅผ ์์ธกํ ์ ์์ผ๋ฏ๋ก ๋ณ๋ ฌ ์ฒ๋ฆฌ ํ ์์์์ง ์ ์ ์๋ค.
- ์ต์ข ์ฐ์ฐ์ ๋ณํฉ ๊ณผ์ ๋น์ฉ์ ์ดํด๋ณด๋ผ.
- ๋ณ๋ ฌ ์คํธ๋ฆผ์ด ์ํ๋ด๋๋ ๋ด๋ถ ์ธํ๋ผ ๊ตฌ์กฐ๋ฅผ ์๊ธฐ์ํด ์ด ํ๋ ์์ํฌ๋ฅผ ์์์ผ ํ๋ค.
- ๊ณผ์ : ์ฌ๊ท์ ์ผ๋ก ์์ ์์ ์ผ๋ก ๋ถํ -> ์๋ธ ํ์คํฌ ๊ฒฐ๊ณผ๋ฅผ ํฉ์น๋ค.
- ํฌํฌ ์๋ฏธ: ๋ค๋ฅธ ์ค๋ ๋๋ฅผ ๋ง๋๋๊ฒ.

- ํ์ํ ๊ณผ์ ์ ์๋ ์ฝ๋์ ๊ฐ๋ค
if (์์
์ด ์ถฉ๋ถํ ์๊ฑฐ๋ ๋์ด์ ๋ถํ ํ ์ ์์ผ๋ฉด) {
// ์์ฐจ์ ์ผ๋ก ์์
๊ณ์ฐ
} else {
// ๋ ์๋ธ์์
์ผ๋ก ๋ถํ
// ํ์คํฌ๊ฐ ๋ค์ ์๋ธ์์
์ผ๋ก ๋ถํ ๋๋๋ก ์ด ๋ฉ์๋๋ฅผ ์ฌ๊ท์ ์ผ๋ก ํธ์ถ
// ๋ชจ๋ ์๋ธ์์
์๋ฃ๊น์ง ๊ธฐ๋ค๋ฆผ
// ์๋ธ์์
๋ค ๊ฒฐ๊ณผ ํฉ์นจ
}- ํฌํฌ/์กฐ์ธ ํ๋ ์์ํฌ๋ฅผ ์ด์ฉํ ๋ณ๋ ฌ ํฉ๊ณ ์ํ
public class ForkJoinSumCalculator
extends java.util.concurrent.RecursiveTask<Long> {
private final long[] numbers; // ๋ํ ์ซ์
private final int start; // ๊ฐ ์๋ธ์์
๋ณ ์์์ซ์
private final int end;
public static final long THRESHOLD = 10_000; // ์ด ๊ฐ ์ดํ๋ก๋ ๋ถํ ๋ชปํ๊ฒ
public ForkJoinSumCalculator(long[] numbers) {
this(numbers, 0, numbers.length);
}
// ์๋ธ์ก ์ฌ๊ท์ ์ผ๋ก ๋ง๋ค ๋น๊ณต๊ฐ ์์ฑ์
private ForkJoinSumCalculator(long[] numbers, int start, int end) {
this.numbers = numbers;
this.start = start;
this.end = end;
}
@Override
protected Long compute() { // RecursiveTask์ ์ถ์ ๋ฉ์๋ ์ค๋ฒ๋ผ์ด๋
int length = end - start;
if (length <= THRESHOLD) {
return computeSequentially();
}
ForkJoinSumCalculator leftTask =
new ForkJoinSumCalculator(numbers, start, start + length/2);
leftTask.fork();
ForkJoinSumCalculator rightTask =
new ForkJoinSumCalculator(numbers, start + length/2, end);
Long rightResult = rightTask.compute();
Long leftResult = leftTask.join();
return leftResult + rightResult;
}
private long computeSequentially() {
long sum = 0;
for (int i = start; i < end; i++) {
sum += numbers[i];
}
return sum;
}
}- ForkJoinPool์ ์ค๋ ๋ ํ๋ก ์์ ์ ์ค๋ ๋์ ๋ถ์ฐ ํ ๋นํ๋ ExecutorService๋ฅผ ๊ตฌํํ๊ณ ์๋ค.
- N: 100,000 ๊ฒฝ์ฐ
- 10๊ฐ๋ก ์ชผ๊ฐ ํ
- ์์์ ์ 1~10,000 ...
- ์ด๋ฐ์์ผ๋ก ์๋๋๊ฒ ์ต๋๋ค.
- ForkJoinSumCalculator 100,000
- Left: ForkJoinSumCalculator 1~50,000
- Left: ...
- Right: ...
- Right: ForkJoinSumCalculator 50,001~100,000
- Left: ...
- Right: ...
- Left: ForkJoinSumCalculator 1~50,000
- ForkJoinSumCalculator 100,000
public static long forkJoinSum(long n) {
long[] numbers = LongStream.rangeClosed(1, n).toArray();
ForkJoinTask<Long> task = new ForkJoinSumCalculator(numbers);
return new ForkJoinPool().invoke(task);
}TIP: ์ผ๋ฐ์ ์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์์๋ ForkJoinPool์ 1๊ฐ์ ์ฑ๊ธํด์ผ๋ก ๋ง๋ค๊ณ ์ฌ์ฌ์ฉํ๋ค.
-
ํด์ฆ: ์ ํ์ชฝ์์๋ง fork()๋ฅผ ์ฐ๊ณ , ๋ค๋ฅธ ํ์ชฝ์ compute()๋ฅผ ์ฌ์ฉํ์๊น?
- ๊ฐ๊ฐ ์ฌ์ฉ์ด ํจ์จ์ ์ด๋ค. -> ๋ ์๋ธํ์คํฌ์ ํ ํ์คํฌ์ ๊ฐ์ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ ์ ์์์ผ๋ก ๋ถํ์ํ ํ์คํฌ ํ ๋น์ ์ค๋ฒํค๋ ๋ฐฉ์งํ๋ค.
-
ํฌํฌ/์กฐ์ธ์์ ๋ณ๋ ฌ ๊ณ์ฐ์ ๋๋ฒ๊น ์ด ์ด๋ ค์ด ์ด์ ๋?
- fork ๋ผ ๋ถ๋ฆฌ๋ ๋ค๋ฅธ ์ค๋ ๋์์, compute๋ฅผ ํธ์ถํจ์ผ๋ก ์คํ ํธ๋ ์ด์ค๊ฐ ๋์๋์ง ์๋๋ค.
-
ํ, ํจ์จ์ ์ฑ๋ฅ์ ์ํด, ์๋ธํ์คํฌ์ ์คํ์๊ฐ > forking ์๊ฐ
// ์๋ ๋์ผ ForkJoinSumCalculator ์ฝ๋
public class ForkJoinSumCalculator
extends java.util.concurrent.RecursiveTask<Long> {
private final long[] numbers;
private final int start;
private final int end;
public static final long THRESHOLD = 10_000;
public ForkJoinSumCalculator(long[] numbers) {
this(numbers, 0, numbers.length);
}
private ForkJoinSumCalculator(long[] numbers, int start, int end) {
this.numbers = numbers;
this.start = start;
this.end = end;
}
@Override
protected Long compute() {
int length = end - start;
if (length <= THRESHOLD) {
return computeSequentially();
}
ForkJoinSumCalculator leftTask =
new ForkJoinSumCalculator(numbers, start, start + length/2);
leftTask.fork();
ForkJoinSumCalculator rightTask =
new ForkJoinSumCalculator(numbers, start + length/2, end);
Long rightResult = rightTask.compute();
// ์๋ join()์...
// ๊ฒฐ๊ณผ๊ฐ ์ค๋น๋ ๋๊น์ง, ํธ์ถ์๋ฅผ ๋ธ๋ก์ํจ๋ค .
// ๊ฐ๊ฐ ์๋ธ ์์
์ด ๋ค๋ฅธ ํ
์คํธ๊ฐ ๋๋๊ธธ ๊ธฐ๋ค๋ฆฌ๋ ์ผ ๋ฐ์์ ๋ง์์ค๋ค.
Long leftResult = leftTask.join();
return leftResult + rightResult;
}
private long computeSequentially() {
long sum = 0;
for (int i = start; i < end; i++) {
sum += numbers[i];
}
return sum;
}
}public static long forkJoinSum(long n) {
long[] numbers = LongStream.rangeClosed(1, n).toArray();
ForkJoinTask<Long> task = new ForkJoinSumCalculator(numbers);
// RecursiveTask์ invoke()๋
// ๋ณ๋ ฌ ๊ณ์ฐ์ ์์ํ ๋๋ง ์ฌ์ฉ
return FORK_JOIN_POOL.invoke(task);
}
public static void main(String[] args) {
forkJoinSum(100_000);
}- N = 1000๋ง ๊ฒฝ์ฐ -> 1000๊ฐ ์ด์ ์๋ธ ํ์คํฌ๋ก ์ชผ๊ฐ์ง๊ฒ
- ํด์ฆ: ์ฝ์ด๊ฐ ์ด๋ ๊ฒ ๋ง์ง๋ ์๋ธํ์คํฌ๋ฅผ ๋ง์ด ์ชผ๊ฐ๋๊ฒ ์ข์๊ฑธ๊น?
- ๋ต: ์ฝ์ด์์ ๊ด๊ณ์์ด ์ ์ ํ ํฌ๊ธฐ๋ก ๋ถํ ๋ ๋ง์ ํ์คํฌ๋ฅผ ํฌํนํ๋ ๊ฒ์ ๋ฐ๋์งํ๋ค.
-
์์
ํ์น๊ธฐ๋ ๋ถํ ๊ธฐ๋ฒ์ด ํจ์จ์ ์ด์ง ์์๋ ๋ฐ์ํ๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํด์ค๋ค.
- ์ญํ : ForkJoinPool์ ๋ชจ๋ ์ค๋ ๋๋ฅผ ๊ณต์ ํ๊ฒ ๋ถํ
- ์๋๊ณผ์
- Doubly LinkedList ์ฌ์ฉ
- ํ๋์ ์ค๋ ๋ ์์ ์ด ๋๋๋ฉด, ๋งํฌ๋๋ฆฌ์คํธ ํ์ ๊ธฐ๋ค๋ฆฌ๋ ๋ค๋ฅธ ์์ ์๊ฒ ๋๊ฒจ์ค๋ค.
- ํ ์์
์๊ฐ ํ์คํฌ๋ฅผ ๋ถํ ํ์๋, ๋ค๋ฅธ ์์
์๊ฐ ํ์น๊ธฐ ๊ฐ๋ฅ
- Spliterator (spliter + iterator): ์๋์ผ๋ก ์คํธ๋ฆผ์ ๋ถํ ํด์ค๋ค. (์๋ฐ 8์์ ๋ฑ์ฅ)
-
๋งํฌ
- ๊ฒฐ๋ก : ~ "๊ธฐ์กด Stream์ผ๋ก๋ ๋ฒ๊ฑฐ๋ก์ด ์์ ๋ค์ ์ข ๋ ์ฝ๊ฒ ์ฒ๋ฆฌ ํ ์ ์์ด, ์ ์ฐ๊ธฐ๋ง ํ๋ค๋ฉด ๋ง์ด ํ์ฉ ํ ์ ์์๊ฒ ๊ฐ์ต๋๋ค."
public interface Spliterator<T> {
// ์์๋ฅผ ์์ฐจ์ ์ผ๋ก ์๋นํ๋ฉฐ ํ์ํ ์์๊ฐ ์์ผ๋ฉด ์ฐธ ๋ฐํ. (iterator๋ ๋น์ท)
boolean tryAdvance(Consumer<? super T> action);
// ์ผ๋ถ์์๋ฅผ ๋ถํ ํด์ ๋๋ฒ์งธ Spliterator๋ฅผ ์์ฑ ๋ฆฌํด
Spliterator<T> trySplit();
// ํ์ํด์ผ๋ ์์์ ์ ๋ณด๋ฅผ ์ ๊ณต
long estimateSize();
// Spliterator์ ํน์ฑ ์งํฉ์ ํฌํจํ๋ int ๋ฐํ
int characteristics(); // ORDERED, DISTINCT, SORTED, SIZED, IMMUTABLE, CONCURRENT, SUBSIZED
}- null์ ๋์ด์ ๋ถํ ๋ถ๊ฐ ์๋ฏธ

- ๊ธฐ์กด ๋ฐ๋ณตํ์ ์ด์ฉํด ๋จ์ด์๋ฅผ ๊ตฌํ ๊ฒฝ์ฐ
final String SENTENCE =
"Nel mezzo del cammin di nostra vita " +
"mi ritrovai in una selva oscura" +
" chรฉ la dritta via era smarrita ";
System.out.println("Found " + countWordsIteratively(SENTENCE) + " words");public int countWordsIteratively(String s) {
int counter = 0;
boolean lastSpace = true;
for (char c : s.toCharArray()) {
if (Character.isWhitespace(c)) {
lastSpace = true;
} else {
if (lastSpace) counter++;
lastSpace = false;
}
}
return counter;
}๊ฒฐ๊ณผ: Found 19 words
- ์๋ ์ฝ๋ ๋ณ๋ ฌ X, ๊ทธ๋ฅ ์คํธ๋ฆผ ์ฒ๋ฆฌ์
- 266~277์ชฝ์ด ์๋ค์...ใ ใ
// main ์ฝ๋
Stream<Character> stream = IntStream.range(0, SENTENCE.length())
.mapToObj(SENTENCE::charAt);
// ๋ง๋ค์ด์ง ์คํธ๋ฆผ: [N, e, l, , m, e, z, z, o, , d, e, l, , c, a, m, m, i, n, , d, i, , n, o, s, t, r, a, , v, i, t, a, , m, i, , r, i, t, r, o, v, a, i, , i, n, , u, n, a, , s, e, l, v, a, , o, s, c, u, r, a, , c, h, รฉ, , l, a, , d, r, i, t, t, a, , v, i, a, , e, r, a, , s, m, a, r, r, i, t, a, ]
System.out.println("Found " + countWords(stream) + " words");private int countWords(Stream<Character> stream) {
WordCounter wordCounter = stream.reduce(new WordCounter(0, true),
WordCounter::accumulate,
WordCounter::combine);
return wordCounter.getCounter();
}class WordCounter {
private final int counter;
private final boolean lastSpace;
public WordCounter(int counter, boolean lastSpace) {
this.counter = counter;
this.lastSpace = lastSpace;
}
//
public WordCounter accumulate(Character c) {
if (Character.isWhitespace(c)) {
return lastSpace ?
this : new WordCounter(counter, true);
} else {
return lastSpace ?
new WordCounter(counter + 1, false) : this;
}
}
// ์๋ธ์์
์์ ๊ณ์ฐ๋ counter๋ค์ ํฉ์น๋ ์ญํ .
public WordCounter combine(WordCounter wordCounter) {
return new WordCounter(counter + wordCounter.counter,
wordCounter.lastSpace);
}
public int getCounter() {
return counter;
}
}๊ฒฐ๊ณผ: Found 19 words
- ์๋ ์ฝ๋ ๋ณ๋ ฌ O
// main ์ฝ๋
// stream์ parallel() ์ถ๊ฐ
System.out.println("Found " + countWords(stream.parallel()) + " words");- ๊ธฐ๋ํ๋ 19 words ๊ฐ ์๋ ๋ค๋ฅธ ๊ฐ...
- ์ด์ : ์๋์ ๋ฌธ์์ด์ ์๋์ ์์น์์ ๋๋ก ๋๋๋ค๋ณด๋ ์์์น ๋ชปํ๊ฒ ํ๋์ ๋จ์ด๋ฅผ ๋๋ก ๊ณ์ฐํ๋ ์ํฉ์ด ์๋ค. ๋ฌธ์จ๋ง?????? ์ฆ, ์์ฐจ ์คํธ๋ฆผ์ ๋ณ๋ ฌ ์คํธ๋ฆผ์ผ๋ก ๋ฐ๊ฟ๋ ๋ถํ ์์น์ ๋ฐ๋ผ ์๋ชป๋ ๊ฒฐ๊ณผ๊ฐ ๋์ฌ ์ ์๋ค.
- ํด๊ฒฐ๋ฒ: ๋จ์ด๋ฅผ ์ค๊ฐ์ด ์๋ ๋๋๋ ์์น๋ฅผ ๊ธฐ์ค์ผ๋ก ๋ถํ ํ์.
๊ฒฐ๊ณผ: Found 25 words
ํด๊ฒฐํ๊ธฐ ์ํด, Spliterator ๋ฅผ ์ฌ์ฉํ ๋๊ฐ ์๋ค!
public static void main(String[] args) {
Spliterator<Character> spliterator = new WordCounterSpliterator(SENTENCE);
Stream<Character> stream = StreamSupport.stream(spliterator, true);
System.out.println("Found " + countWords(stream) + " words");
}
private static int countWords(Stream<Character> stream) {
WordCounter wordCounter = stream.reduce(new WordCounter(0, true),
WordCounter::accumulate,
WordCounter::combine);
return wordCounter.getCounter();
}class WordCounterSpliterator implements Spliterator<Character> {
private final String string;
private int currentChar = 0;
public WordCounterSpliterator(String string) {
this.string = string;
}
@Override
public boolean tryAdvance(Consumer<? super Character> action) {
action.accept(string.charAt(currentChar++));
return currentChar < string.length();
}
@Override
public Spliterator<Character> trySplit() {
int currentSize = string.length() - currentChar;
if (currentSize < 10) {
return null;
}
for (int splitPos = currentSize / 2 + currentChar; splitPos < string.length(); splitPos++) {
if (Character.isWhitespace(string.charAt(splitPos))) {
Spliterator<Character> spliterator =
new WordCounterSpliterator(string.substring(currentChar,
splitPos));
currentChar = splitPos;
return spliterator;
}
}
return null;
}
@Override
public long estimateSize() {
return string.length() - currentChar;
}
@Override
public int characteristics() {
return ORDERED + SIZED + SUBSIZED + NON-NULL + IMMUTABLE;
}
}๊ฒฐ๊ณผ: Found 19 words
- ๋ด๋ถ ๋ฐ๋ณต์ ์ด์ฉํ๋ฉด, ๋ช ์์ ์ผ๋ก ๋ค๋ฅธ ์ค๋ ๋๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ ์คํธ๋ฆผ์ ๋ณ๋ ฌ ์ฒ๋ฆฌ ๊ฐ๋ฅ
- ํญ์ ๋ณ๋ ฌ ์ฒ๋ฆฌ๊ฐ ๋น ๋ฅธ๊ฒ์ ์๋. (์ง์ ์ฑ๋ฅ ์ฒดํฌ ํ์)
- ์ฒ๋ฆฌํ ๋ฐ์ดํฐ๊ฐ ๋ง๊ฑฐ๋ ๊ฐ ์์ ์ฒ๋ฆฌ ์ค๋์๊ฐ ๊ฑธ๋ฆด๋ ๋ณ๋ ฌ์คํธ๋ฆผ ์ถ์ฒ
- ์ฑ๋ฅ์ ์ํด, ๊ธฐ๋ณธํ ํนํ ์คํธ๋ฆผ ์ฌ์ฉ ๊ถ์ฅ
- ํฌํฌ/์กฐ์ธ์ ์๋ธํ์คํฌ๋ก ๋ถํ ํ ๊ฐ ์ค๋ ๋์์ ์ฒ๋ฆฌํ ๋จธ์ง
- Spliterator๋ ํ์ํ๋ ค๋ ๋ฐ์ดํฐ๋ฅผ ํฌํจํ๋ ์คํธ๋ฆผ์ ์ด๋ป๊ฒ ๋ณ๋ ฌํํ ๊ฒ์ธ์ง ์ ์