1. {1, 2, 3, 4, 5} の並列合計は 15
  2. 空配列 {} の並列合計は 0
  3. 要素 1 つ {100} の並列合計は 100
  4. {-5, 5, -10, 10} の並列合計は 0 (プラマイ相殺)
  5. {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} の並列合計は 55
コース一覧
Java 中級:コレクション・Stream・例外処理
並列ストリーム

Java 中級:コレクション・Stream・例外処理

コレクション、ジェネリクス、例外処理、Stream API、関数型インターフェース、日付処理、ファイル I/O、継承など Java の中級トピックを実践的に学べるコースです。Java の基礎文法とオブジェクト指向を理解している学習者を対象に、現場の Java コードを読み書きするための知識を補強します。約 16 時間 (1 日 30 分 × 32 日) で 64 レッスンを修了でき、修了後は Spring Boot や業務システム開発に必要な Java 力が身につきます。

1
コレクション基礎
01. ArrayList を使う5分
02. List を走査する5分
03. 要素の削除と検索5分
04. HashMap の基本5分
05. Map を走査する5分
06. Set で重複を排除5分
07. Collections クラスの便利メソッド5分
08. コレクション基礎 まとめクイズ5分
2
ジェネリクス
01. ジェネリッククラスを作る5分
02. ジェネリックメソッド5分
03. 境界型パラメータ5分
04. ワイルドカード ?5分
05. Pair<K,V> を作る5分
06. ジェネリクス まとめクイズ5分
3
例外処理
01. try-catch で例外をつかむ5分
02. 複数の catch ブロック5分
03. throws と例外の伝播5分
04. 独自の例外を作る5分
05. try-with-resources5分
06. finally ブロック5分
07. 例外処理 まとめクイズ5分
4
Stream API
01. Stream を作る5分
02. filter で絞り込む5分
03. map で変換する5分
04. reduce で集約する5分
05. collect で集める5分
06. sorted で並び替え5分
07. distinct で重複排除5分
08. limit と skip5分
09. 並列ストリーム5分
10. Stream API まとめクイズ5分
5
関数型インターフェース
01. ラムダ式の基本5分
02. メソッド参照 ::5分
03. Function インターフェース5分
04. Predicate インターフェース5分
05. Consumer と Supplier5分
06. BiFunction と 2 引数の関数5分
07. 関数型インターフェース まとめクイズ5分
6
文字列操作
01. String.format で書式化5分
02. StringBuilder で連結5分
03. 正規表現の基本5分
04. split と join5分
05. 文字列操作 まとめクイズ5分
7
日付と時刻
01. LocalDate で日付を扱う5分
02. LocalDateTime で時刻も扱う5分
03. Duration で時間差を計算5分
04. 日付の書式化とパース5分
05. 日付の加減算5分
06. 日付と時刻 まとめクイズ5分
8
ファイル I/O
01. Files でファイルに書き込む5分
02. ファイルを行単位で読む5分
03. Path でファイルパスを扱う5分
04. BufferedReader と Stream API5分
05. ファイルの存在確認と削除5分
06. ファイル I/O まとめクイズ5分
9
継承とポリモーフィズム
01. extends で継承する5分
02. super で親を呼ぶ5分
03. メソッドのオーバーライド5分
04. abstract で抽象クラス5分
05. interface で契約を定義5分
06. default メソッド5分
07. instanceof と型パターン5分
08. ポリモーフィズムを活かす5分
09. 継承とポリモーフィズム まとめクイズ5分

並列ストリーム

1 行足しただけで、速くなるはずがない

Stream には parallel() という中間操作があります。これを挟むと、要素が分割されて複数の CPU コアで同時に処理されます。

Java

long hits = logs.stream() .parallel() .filter(line -> line.contains("ERROR")) .count();

追加したのは 1 行だけです。それで速くなるなら、全部の Stream に付ければよさそうに思えます。ところが実際に時間を測ると、多くの場合は変わらないか、むしろ遅くなります。

理由は、並列化そのものにも手間がかかるからです。要素を分けて、それぞれのコアに配って、終わったら結果を合わせる。この段取りに時間を使います。1 件あたりの処理が軽ければ、段取りの時間の方が大きくなります。数十件から数百件のリストを流す程度では、まず割に合いません。

parallel() は「速くする道具」ではなく「速くなるかもしれない試し方」です。付けるかどうかは、両方の書き方で実際に時間を測ってから決めます。

順番が保証されなくなる

速さ以前に、動きが変わる点があります。forEach の処理される順番です。

Java

List.of("a", "b", "c", "d").parallelStream() .forEach(s -> System.out.println(s));

これを何度か実行すると、出てくる順番が毎回変わります。分割された塊が、終わった順に処理されるからです。並んだ順に出したいなら forEachOrdered を使いますが、そうすると順番を待つ分だけ並列にした意味が薄れます。

collect(Collectors.toList()) のように結果を集める終端操作なら、元の順番は保たれます。順番が崩れて困るのは、処理の途中で表示や書き込みをしている場合です。

共有している変数を書き換えると壊れる

もう 1 つ、こちらの方が深刻です。

Java

List<String> found = new ArrayList<>(); logs.parallelStream() .filter(line -> line.contains("ERROR")) .forEach(line -> found.add(line)); // 危ない

ArrayList は、複数のスレッドから同時に追加されることを想定していません。同時に add が走ると、要素が入らずに消えたり、例外が出たりします。しかもいつも壊れるわけではなく、たまに壊れます。テストでは通って本番で落ちる、いちばん厄介な種類のバグです。

結果を集めたいときは、自分で用意したリストに詰めるのではなく collect を使います。collect は並列でも安全に集まるように作られています。

解説

直列で書いてあるコードに parallel() を足すだけで壊れる、ということは、元のコードがラムダの外側を書き換えていたということです。並列化を試すのは、そういう書き方をしていないか点検する良い機会にもなります。

やってみよう

Solution.parallelSum(int[] arr) を完成させて、配列の合計を返してください。

ファイルの先頭に import java.util.Arrays; を書き、Arrays.stream(arr) で IntStream を作ります。そこに .parallel() を挟んでから、.sum() で合計を取ります。

今回の目的は、並列にしても答えが変わらないことを確かめることです。テストの配列は数件しか無いので、速くはなりません。むしろ直列より時間がかかります。合計のように「どこで区切って足しても答えが同じ」になる計算だから、分けて足して後から合わせても結果が一致する、というところを見てください。

要件

  1. ファイル先頭で import java.util.Arrays; を書くこと
  2. Arrays.stream(arr) で IntStream を作り、.parallel() で並列モードに切り替えること
  3. 最後に .sum() を呼んで合計の int を return すること

入出力例

parallelSum([1,2,3,4,5]) → 15 parallelSum([]) → 0 parallelSum([100]) → 100 parallelSum([-5,5,-10,10]) → 0 parallelSum([1,2,3,4,5,6,7,8,9,10]) → 55

ヒント

`Arrays.stream(int[])` は `IntStream` を返すので、`Stream<Integer>` ではなく `IntStream` 専用の `sum()` がそのまま使えます

`.parallel()` を呼ぶ位置はパイプラインの途中ならどこでも OK。今回は `Arrays.stream(arr).parallel().sum()` の順で書くのが最短です

`sum` は結合的 (`(a+b)+c == a+(b+c)`) なので、並列で配列をどう分割しても結果は変わりません。直列の `Arrays.stream(arr).sum()` と同じ値が返ります

生田 陸人
監修生田 陸人
ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
編集 ゆめさく編集部·公開 2026/05/19·更新 2026/08/26

関連レッスン

  • Stream API まとめクイズ

    Stream API 章で学んだ生成 / filter / map / reduce / collect / sorted / distinct / limit / skip / parallel を、メソッドチェーンの順序と中間操作・ターミナル操作の使い分けで総ざらいする 4 択クイズ。

  • ラムダ式の基本

    Java 8 から導入されたラムダ式の文法と関数型インターフェースの考え方を学び、Stream と組み合わせて配列の合計を一行で書く感覚を身につけよう。

  • String.format で書式化

    `Java` の `String.format` で `%s` `%d` `%,d` `%.2f` などの書式指定子を使い、整形された文字列を組み立てる方法を学ぼう。

  • LocalDate で日付を扱う

    Java 8 で導入された java.time.LocalDate を使って、日付の生成・加減算・整形を学び、年月日から ISO 形式の文字列を返すコードを書いてみよう。

このレッスンに出てくる用語

意味があいまいなまま進んだ語は、ここから読み直せます。

  • 処理計算や代入を表す長方形
  • リスト順序付きで複数の値を扱うデータ構造
  • 変数データに名前をつけて参照する仕組み
  • スレッド1 つの質問に紐づく返信の集まり
  • テストバグを見つける工程
  • 配列サイズ固定の同型データの集まり
main.java
学習モード
エディタを読み込んでいます

メモ

並列ストリーム

⌘S で保存