1. 3 行の数値を合計する
  2. 1 行だけならその値を返す
  3. 空文字列なら 0
  4. 2 行の大きめの数値を合計する
  5. 末尾に改行がある入力も同じ結果を返す
  6. 途中に空行が混ざっても無視して合計する
コース一覧
Java 中級:コレクション・Stream・例外処理
BufferedReader と Stream API

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分

BufferedReader と Stream API

1 GB のログを読もうとして、プログラムが落ちる

前回の Files.readAllLines は、ファイル全体を List に詰めて返します。数 KB の設定ファイルなら申し分ありませんが、1 GB のアクセスログに同じことをすると、全行がメモリに載った時点で OutOfMemoryError になります。行を 1 つ見るたびに前の行は用済みなのに、最後まで全部抱え込んでしまうのが原因です。

Files.lines は、同じファイルを Stream<String> として返します。読むのは必要になった行だけで、処理が終わった行はそのまま捨てられます。手元に残るのは常に 1 行分だけなので、ファイルがどれだけ大きくてもメモリは増えません。

Java

import java.nio.file.Files; import java.nio.file.Path; import java.util.stream.Stream; public class Demo { public static void main(String[] args) throws Exception { Path p = Path.of("access.log"); try (Stream<String> lines = Files.lines(p)) { long errors = lines.filter(line -> line.contains("ERROR")).count(); System.out.println(errors); } } }

1 行が Stream の 1 要素になるので、これまで使ってきた filter や map、count がそのまま通用します。改行が \n か \r\n かの判定は内側で済んでいて、こちら側で意識することはありません。

閉じ忘れると、あるとき突然 Too many open files で死ぬ

Stream というと、ただの値の流れに見えて閉じるものだと思いにくいのですが、Files.lines が返す Stream は裏でファイルを開いたまま握っています。放置すると OS のファイルディスクリプタが 1 つずつ残り、何百回か呼んだところで上限に達して Too many open files で落ちます。しかも落ちるのは、開きっぱなしにした場所ではなく、そのあとの何でもない処理です。

そのため Files.lines は必ず try の丸括弧の中で開きます。ブロックを抜けるときに自動で閉じられるので、途中で例外が出ても、return で抜けても取りこぼしがありません。

閉じる必要があるのは、このように外の世界とつながっている Stream だけです。メモリ上のデータから作った Stream は握っているものが無いので、丸括弧に入れる必要はありません。

Java

try (Stream<String> lines = Files.lines(p)) { // ファイルを握っている // ... } names.stream().filter(s -> !s.isEmpty()).count(); // 握っていないので閉じない

空行を数値に変換しようとして落ちる

Stream の途中に例外が出る処理を挟むときは、渡ってくる行を疑ってください。数値が 1 行に 1 つ並んだファイルでも、間に空行が 1 つ混ざっていれば Integer.parseInt("") が呼ばれ、NumberFormatException で止まります。手で編集されたファイルや、他のシステムが吐いたファイルでは十分ありえます。

対策は単純で、変換の前に filter で空行を落としておくことです。s.isEmpty() が true の行を通さないようにすれば、あとの処理は数字だけを相手にできます。

解説

Stream<String> から数値の合計を出したいときは、mapToInt を通して IntStream に変えます。IntStream には sum average max が最初から用意されているので、自分で合計用の変数を持ち回る必要がありません。

やってみよう

Solution.sumOfNumbers(String content) を完成させます。1 行に 1 つ整数が書かれた文字列を受け取り、その合計を返します。

  1. 一時ファイルを作り、受け取った content を書き込む
  2. そのファイルを Files.lines で開く。try の丸括弧の中で開き、抜けるときに閉じること
  3. 空行を除いてから整数に変換し、合計を int で return する

sumOfNumbers("1\n2\n3") は 6、sumOfNumbers("") は 0 です。空文字列のときは行が 1 つも流れてこないので、合計は自然に 0 になります。

要件

  1. Files.createTempFile と Files.writeString で content を一時ファイルに書き出すこと
  2. try-with-resources で Files.lines(path) を開き、抜けるときに Stream を自動で閉じること
  3. filter で空行を除外し、mapToInt(Integer::parseInt) と sum() を使って int の合計を返すこと

入出力例

sumOfNumbers("1 2 3") → 6 sumOfNumbers("10") → 10 sumOfNumbers("") → 0 sumOfNumbers("100 200") → 300 sumOfNumbers("1 2 3 ") → 6 sumOfNumbers("5 7 8") → 20

ヒント

`Files.lines(path)` は `Stream<String>` を返します。`try (Stream<String> lines = Files.lines(path)) { ... }` の形で囲むと自動で `close` されます

メソッド参照 `Integer::parseInt` は `s -> Integer.parseInt(s)` と同じ意味です。`mapToInt` の引数にそのまま渡せます

空行を弾かないと `Integer.parseInt("")` で `NumberFormatException` が出ます。`filter(s -> !s.isEmpty())` を挟みましょう

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

関連レッスン

  • ファイルの存在確認と削除

    Files.exists / Files.delete などの基本 API を使い、一時ファイルを作って存在を確認し、削除してからもう一度確認するコードを書いてみよう。

  • ファイル I/O まとめクイズ

    ファイル I/O 章 (Files / Path / BufferedReader / try-with-resources) の総まとめ。書き込み API の使い分け、リソースの自動 close、文字コード、例外処理の組み合わせを 4 択クイズで再確認する。

  • extends で継承する

    Java の `extends` キーワードを使った継承の基本を学び、`Animal` を継承した `Dog` クラスを作って `Dog.bark()` の結果を返すコードを書いてみよう。

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

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

  • メモリプログラムとデータを一時保持する高速領域
  • 処理計算や代入を表す長方形
  • ロック「他の人触らないでね」と DB に予約する
  • 変数データに名前をつけて参照する仕組み
main.java
学習モード
エディタを読み込んでいます

メモ

BufferedReader と Stream API

⌘S で保存