第04章 Java応用

04_java_advanced

第04章 Java実践 — 例外処理・コレクション・Stream API・ファイル操作

この章の読み方: 本文の基本説明、直後の発展解説、例題、演習の順に読んでください。専門用語は初めて出てきた箇所で意味を確認し、コードの予想結果を考えてから実行します。

章末の演習は、それまでの本文の内容を使って解けるように設計しています。

用語の表記: 全10章共通の用語集 と表記を揃えています。

対象:プログラミング未経験者/Javaを初めて学ぶ他言語経験者
推奨環境:Windows 11、JDK 21、Eclipse(無料・ローカルPC)
位置づけ:第03章「オブジェクト指向」の次に学習する章

この章は、初めてJavaを学ぶ人が、用語の意味や操作する理由を確認しながら自習できるように構成しました。

本文にある短いコードは考え方の説明であり、実際にコンパイル・実行する場合は examples/04_java_advanced/ に収録した完成したサンプルファイルを使用してください。


独学演習: 学んだ内容の確認には、第04章の実行予想・段階別ヒント・自己チェックを使ってください。本文の説明を読んだあと、自分で出力を予想してから試します。

00. この章を始める前に

第03章では、クラスを作り、商品や注文などの情報と処理をまとめる方法を学びました。しかし、実際のシステムでは商品が1件だけとは限りません。商品が100件ある場合はどのように管理すればよいでしょうか。

また、ファイルが存在しない、数値として読み取れない、入力内容が間違っているといった問題が発生したとき、プログラムをどうすればよいでしょうか。

第04章では、複数のデータを扱うコレクション、問題発生に対処する例外処理、データを抽出・集計するStream API、ファイルを読み書きする入出力処理を学びます。

最初は聞き慣れない言葉が多く感じるかもしれませんが、すべて業務アプリケーションで頻繁に使う仕組みです。

学習目標:①例外が起こる理由と処理方法を説明できる、② List・Set・Map を使い分けられる、③ジェネリクスと拡張for文を使える、④Stream APIを使って条件抽出と集計ができる、⑤ UTF-8のテキストファイルを安全に読み書きできる、⑥エラーのある入力を扱う簡単な商品集計プログラムを作れる。

前提:JDK 21とEclipseをセットアップ済みで、第02章の if、for、メソッド、第03章のクラスとコンストラクタを学習していること。サンプルは節ごとに独立しています。

各節の Main.java を別々のJavaプロジェクトに配置するか、フォルダーごとにコマンドプロンプトからコンパイルします。

Javaファイルを直接開いて実行するだけでなく、どのフォルダーが実行時の基準になっているか確認してください。

学習時間の目安:約8〜12時間(復習を含む)。理解度によって必要時間は変わります。用語が分からない場合は先の節へ進まず、短いサンプルを変更して実行結果を確認しましょう。


この節の独学チェック:00. この章を始める前に

確認問題: 商品が100件になり、CSVの価格列に「abc」が混ざった場合、第04章で何を学ぶ必要がありますか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

商品100件を1変数でまとめて扱うためのJavaの仕組みを探してください。

ヒント2

価格文字列を整数へ変換するとき、「abc」が入力されると何が起こるか考えてください。

ヒント3

ListとInteger.parseIntを組み合わせ、行単位でNumberFormatExceptionを処理する構成を考えてください。

模範解答と理由

複数の商品はListなどのコレクションで扱い、abcの数値変換失敗はNumberFormatExceptionとして行単位で扱います。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: 100件の商品の格納にはListなどのコレクションを使う
  2. 1点: "abc"の数値変換失敗を検出し、対象行ごとに例外処理する

正答例: Listで100件を持ち、価格「abc」は変換時の例外をその行で扱う。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: Listを選べるが、「abc」も通常の数値として集計できると答える。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: 商品100件を1変数でまとめて扱うためのJavaの仕組みを探してください。

01. エラーと例外の基本

プログラムには、書き方を間違えたためにコンパイルできない問題と、コンパイルできても実行中に問題が起きる場合があります。

例えば int x = "abc"; は文字列を整数型の変数に入れようとしているため、通常はコンパイルエラーになります。

一方、Integer.parseInt("abc") は文法的には正しくても、実行時には文字列を整数に変換できません。

Javaでは、実行中の異常な状態を表すために**例外(exception)**という仕組みを使います。Integer.parseInt に数字以外の文字列を渡すと、NumberFormatException が発生します。

例外が適切に処理されなければ、通常そのスレッドの処理はそこで終わり、エラー内容が表示されます。これは必ずしもPCの故障を意味しません。

下のプログラムは、文字列の数字を整数に変換します。Integer.parseInt は変換するメソッドです。120 は数値として読めるので、そのまま表示できます。

String text = "120";
int quantity = Integer.parseInt(text);
System.out.println(quantity);

text を "abc" に変更すると、NumberFormatException が発生します。表示されるエラーメッセージと、その後の行が実行されたかに注目しましょう。

エラーを単に「失敗」と見るのではなく、どの行で何が起きたかを特定する手がかりと考えるのが重要です。


この節の独学チェック:01. エラーと例外の基本

確認問題: int x = "abc" と Integer.parseInt("abc") は、それぞれどの時点で失敗しますか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

代入先がintの場合、右辺の型をまず確認してください。

ヒント2

Integer.parseIntの戻り値の型と、引数に許される文字列の内容を分けて考えてください。

ヒント3

コンパイル時の型検査と、実行時の数値変換を区別して結論を出してください。

模範解答と理由

前者は型が合わないためコンパイル時、後者は実行時にNumberFormatExceptionが発生します。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: int x = "abc"はコンパイル時に型不一致で失敗する
  2. 1点: Integer.parseInt("abc")は実行時にNumberFormatExceptionになる

正答例: 前者はコンパイルエラー、後者はコンパイルできるが実行時にNumberFormatException。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: 両方ともコンパイルエラーになる。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: 代入先がintの場合、右辺の型をまず確認してください。

02. try / catch / finally を使う

実行中の例外に対処するために try と catch を使います。try の波括弧 {} に例外が起こり得る処理を書き、catch に例外が起きた場合の対応を書きます。

catch (NumberFormatException e) の e は発生した例外の情報を持つ変数です。

try {
    int quantity = Integer.parseInt("abc");
    System.out.println(quantity);
} catch (NumberFormatException e) {
    System.out.println("数量は整数で入力してください。");
}
System.out.println("処理を終了しました。");

この例では、整数に変換できないときに、利用者が理解できる案内を表示します。try の途中で例外が発生すると、残りの try 内の処理は実行されず、該当する catch に進みます。

catch が終われば、通常は後続の処理を続けられます。

finally は、例外が起きたかどうかにかかわらず行いたい終了処理を書くための仕組みです。ただし、ファイルなど閉じる必要がある資源には、後で学ぶ try-with-resources を優先しましょう。

finally が常に実行されると断言できるわけではありません(プロセスが強制終了された場合などは実行されません)。

例外を処理するときの注意:catch (Exception e) { } のように空のまま何もしないと、異常の原因を調べられなくなります。

対応できない例外を無理に握りつぶさず、必要に応じて呼び出し元へ伝えるか、ログなどに状況を残すことが大切です。業務では、利用者向けの案内と、開発者が調査するための情報を分ける場合があります。

試すファイル:examples/04_java_advanced/01_exception/Main.java。最初は "120"、次は "abc" として実行し、表示の違いを書き留めてください。


理解を深める:例外を区別して扱う

チェック例外はコンパイル時に処理または宣言を求められる例外です。IOException が代表例です。

IllegalArgumentException などの非チェック例外はコンパイル時に処理を強制されません。例外を捕まえて何もせず続けると、問題が隠れます。

業務上処理できるなら回復し、回復できないなら原因が分かるように上位へ伝える方針を検討します。

try {
    int count = Integer.parseInt("abc");
    System.out.println(count);
} catch (NumberFormatException e) {
    System.err.println("整数として読めません: " + e.getMessage());
}

例外を受け取った場合、どの入力値が原因かを確認します。ただしパスワードや個人情報など、秘密の値をログへ記録してはいけません。

この節の独学チェック:02. try / catch / finally を使う

確認問題: tryで例外が出たときcatchとfinallyはどう動きますか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

tryで例外が起きた直後、後続のtry内の文が実行されるか考えてください。

ヒント2

catchに書かれた例外型が、発生した例外に対応するか確かめてください。

ヒント3

finallyに置いた後片付けが正常系・異常系でどう扱われるか追ってください。

模範解答と理由

対応するcatchが例外を処理し、finallyは通常、例外の有無によらず実行されます。System.exitなど例外的な状況は除きます。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: 一致するcatchがあれば例外を捕捉して処理する
  2. 1点: finallyは通常、例外発生の有無にかかわらず実行される

正答例: 対応するcatchへ移り、通常は最後にfinallyも実行される。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: 例外が起きた場合にはfinallyは絶対に実行されない。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: tryで例外が起きた直後、後続のtry内の文が実行されるか考えてください。

図解:例外処理の流れ

例外処理の流れ

図の読み方:finallyは基本的に正常・例外のいずれの経路でも実行されます。

03. throw と throws、例外の種類

throw は自分で例外を発生させる命令です。例えば、商品の価格をマイナスで設定させたくないとき、コンストラクタの中で throw new IllegalArgumentException("価格は0以上にしてください。"); と書けます。入力を受け取った直後にチェックすれば、以降の処理が不正な値を前提に進むことを防ぎやすくなります。

throws は、メソッドの宣言部分に書き、そのメソッドから呼び出し元へ例外が伝わる可能性を表すものです。特にコンパイラが処理を要求するチェック例外(IOException など)について重要です。

NumberFormatException や IllegalArgumentException は非チェック例外で、メソッドに throws と明記する義務はありません。

public static int parseQuantity(String text) {
    int quantity = Integer.parseInt(text);
    if (quantity < 0) {
        throw new IllegalArgumentException("数量は0以上にしてください。");
    }
    return quantity;
}

ここで大切なのは「すべての場所で try/catch する」のではない、という点です。利用者に入力のやり直しを案内できる場所、システム全体としてエラーを報告する場所など、対応する責任を持つ場所で扱うことが基本です。

試すファイル:02_validation/Product.java と Main.java。この Product クラスは第03章のクラス・コンストラクタを復習できるようにしています。

エラー時には new Product が正常に完了しないことも確認してください。


理解を深める:例外を無視して処理を続けず、呼び出し元へ問題を伝える

ファイルが見つからない・数字として読めないなど、通常の処理を続けられない状態を例外で表します。try は例外が発生しうる範囲、catch は例外を受けてどう対処するかを書く場所です。

try {
    int quantity = Integer.parseInt("abc");
    System.out.println(quantity);
} catch (NumberFormatException e) {
    System.out.println("数量は整数で入力してください");
}

この例は入力し直せる場面なので適切なメッセージに変換しています。ただし、原因を調べる必要がある実務処理では、単に catch (Exception e) {} と空にしてはいけません。

エラーを隠すとデータの欠落や誤処理につながります。IOException のようなチェック例外は、原則として捕捉か throws による宣言が必要です。NumberFormatException は非チェック例外です。

この節の独学チェック:03. throw と throws、例外の種類

確認問題: throw new IllegalArgumentException(...) と throws IOException の違いは何ですか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

2つのキーワードがメソッド本体と宣言部のどちらに現れるか確認してください。

ヒント2

new IllegalArgumentException(...) は例外オブジェクトを作っています。その後何をしているでしょうか。

ヒント3

throws IOExceptionはその行でIOExceptionを生成するのか、呼び出し元へ可能性を示すのか考えてください。

模範解答と理由

throwは実際に例外を発生させ、throwsはメソッド宣言で呼び出し側に伝わる可能性を示します。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: throwは処理中に例外オブジェクトを投げる文である
  2. 1点: throwsはメソッド宣言で送出し得る例外型を宣言する

正答例: throwは実際に投げ、throwsはメソッドが送出し得る型を宣言する。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: throws IOExceptionと書いただけでその行で必ずIOExceptionが発生する。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: 2つのキーワードがメソッド本体と宣言部のどちらに現れるか確認してください。

04. コレクションとは何か

第02章では配列を学びました。配列は複数の値を一つにまとめられますが、作成時に要素数を決めます。商品が何件あるか事前に分からない場合、件数に応じて要素を追加したいことがあります。このような場合に役立つのがコレクションです。

コレクションは、複数のオブジェクトをまとめて扱うための仕組みです。Javaには用途に応じてさまざまな種類が用意されています。代表的なものは List、Set、Map です。

List は順番のある要素の集まりで重複を許可し、Set は重複する要素を持たない集まり、Map はキーと値の組を使って情報を管理します(厳密には Map は Collection インターフェースのサブタイプではありませんが、学習上は関連する仕組みとして扱います)。

例えば、購入した商品を順番に表示するなら List、登録済みの会員IDを重複なく管理するなら Set、商品コードから価格を調べたいなら Map が候補です。

最初からすべてを暗記せず、どんな形でデータを取り出したいかで選ぶことを意識しましょう。


理解を深める:配列だけでは困る理由

配列の長さは生成時に決まります。人数や商品数が後から増える場合、ArrayList なら要素を追加できます。List は順番を持ち重複を許す集合、Set は重複を許さない集合、Map はキーから値を探す構造です。

用途が違うので「どれが上位互換か」で選びません。

したいこと 代表的な選択 理由
注文商品を入力順に並べる List 順序と同じ商品の重複を残す
重複しない商品コードを集める Set 重複を除外する
商品コードから商品名を探す Map<String, String> キーによる検索を表す
List<Integer> prices = new ArrayList<>();
prices.add(120);
prices.add(250);
prices.add(120);
int sum = 0;
for (int price : prices) { sum += price; }
System.out.println(sum); // 490

add は末尾に値を追加します。拡張for文は要素を一つずつ取り出します。sum += price は sum = sum + price と同じ意味です。重複した120円も別の購入行として合計しています。

この節の独学チェック:04. コレクションとは何か

確認問題: 商品1件を表すProductと商品100件を持つListは何が違いますか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

Productのフィールドに何を持たせるか、1件の例を作ってください。

ヒント2

商品が100件ある場合、Product型の変数1つだけで全件を保持できるか考えてください。

ヒント3

Listにaddで複数の商品を追加し、getで取り出すイメージを確認してください。

模範解答と理由

Productは商品1件の属性を表し、Listは複数のProductへの参照を順序付きで保持します。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: Productは商品1件の属性を表すクラスまたはそのインスタンスの型である
  2. 1点: Listは複数の商品を順序付きで格納するコレクションの型である

正答例: Productは1商品の型、Listは多数のProduct要素を順序付きで保持する型。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: Listは商品1件を表し、Productは商品100件を保存する。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: Productのフィールドに何を持たせるか、1件の例を作ってください。

05. List と ArrayList

List は要素を追加した順序で管理でき、同じ値を複数回登録できます。ArrayList は、その List を実現するクラスです。

Javaでは変数の型を List<String>、実際に作成するものを new ArrayList<>() と書くことが多くあります。

これは使い方の約束である List と、具体的な実装である ArrayList を分けるためです。

List<String> names = new ArrayList<>();
names.add("ノート");
names.add("ペン");
System.out.println(names.get(0));
System.out.println(names.size());

この例で add は要素の追加、get(0) は最初の要素の取得、size() は要素数の取得です。Javaの添字は0から始まるため、要素が2個なら有効な添字は0と1です。

存在しない添字を取得しようとすると IndexOutOfBoundsException が発生します。

List を繰り返し処理する場合は、拡張for文が分かりやすいことが多いです。

for (String name : names) {
    System.out.println(name);
}

「names にある各要素を一つずつ name に取り出す」と読むと理解しやすくなります。試すファイル:03_list/Main.java。

さらに names.add("ノート") を追加して、重複が残ることを確認してください。


この節の独学チェック:05. List と ArrayList

確認問題: List.of("A","B").get(1) の結果と、get(2)の結果を答えてください。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

Listのインデックスは0から始まることを確認してください。

ヒント2

"A"と"B"それぞれに0と1の添字を付けてください。

ヒント3

要素数2のリストで有効な添字の最大値を求めてください。

模範解答と理由

get(1)はBです。要素数2の添字は0と1なのでget(2)はIndexOutOfBoundsExceptionです。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: List.of("A","B").get(1)はBである
  2. 1点: 同リストのget(2)はIndexOutOfBoundsExceptionを投げる

正答例: get(1)はB。get(2)は範囲外なのでIndexOutOfBoundsException。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: get(1)がAで、get(2)がB。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: Listのインデックスは0から始まることを確認してください。

06. Set と Map を使い分ける

Set は重複のない集まりを扱います。例えば HashSet<String> に "A01" を2回追加しても、同じ文字列なら要素数は増えません。ただし HashSet は登録順の表示を保証しません。

順番が重要なら、用途に合った別の実装を検討する必要があります。

Map はキーを指定して値を取り出します。Map<String, Integer> なら、キーが String(商品コード)、値が Integer(価格)の組です。

put("A01", 120) で登録し、get("A01") で値を取り出します。

指定したキーが存在しない場合、HashMap の get は null を返すため、すぐに整数として計算すると問題になる場合があります。containsKey などを使って確認します。

Map<String, Integer> prices = new HashMap<>();
prices.put("A01", 120);
System.out.println(prices.containsKey("B02")); // false

Map で同じキーにもう一度 put すると、以前の値は新しい値で置き換えられます。重複を許さないことと、エラーになることは同じではありません。この違いにも注意してください。

試すファイル:04_set_map/Main.java。


理解を深める:List・Set・Mapの選び方

保存したい内容 適切な候補 理由
登録順に商品を並べたい List<Product> 同じ要素も複数登録でき、順序を持つ
重複する商品IDを除外したい Set<String> 重複を許さない
IDから商品を探したい Map<String,Product> キーを使って値を取り出せる
List<String> list = new ArrayList<>();
list.add("A");
list.add("A");
System.out.println(list.size()); // 2
Set<String> set = new HashSet<>(list);
System.out.println(set.size());  // 1
Map<String, Integer> stock = new HashMap<>();
stock.put("A", 3);
System.out.println(stock.get("A")); // 3

HashSet と HashMap は並び順の維持を保証しません。画面に表示する順番が必要な場合は、ソートするか順序を保証する実装を選びます。

この節の独学チェック:06. Set と Map を使い分ける

確認問題: 重複しない商品IDと、商品IDから商品名を検索する情報を管理するにはSetとMapのどちらを使いますか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

必要なのは単純なIDの集合か、IDと商品名の対応かを分けてください。

ヒント2

同じIDを二度登録した場合に重複を保持する必要があるか考えてください。

ヒント3

Mapのput(ID, 商品名)とget(ID)が何を扱うか確認してください。

模範解答と理由

重複しないIDの集合はSet、IDをキーとして商品名を対応付けるならMapが適します。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: 商品IDの重複を避けて保持するにはSetが適する
  2. 1点: IDをキーに商品名を引くにはMapが適する

正答例: 重複のないIDにはSet、IDから商品名を引くにはMap。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: IDから商品名を引く用途はSetだけで十分。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: 必要なのは単純なIDの集合か、IDと商品名の対応かを分けてください。

図解:List / Set / Map

List / Set / Map

図の読み方:Listは順序、Setは重複排除、Mapはキーによる検索が特徴です。

07. ジェネリクスと型安全

List<String> や Map<String, Integer> の山括弧 <> は、コレクションなどが扱うデータの型を指定する仕組みです。これを**ジェネリクス(generics)**と呼びます。

List<String> は文字列を扱うことを表すため、誤って Integer を追加しようとするとコンパイル時点で問題を見つけやすくなります。

List<Product> なら、第03章で作った商品クラスのオブジェクトを複数管理できます。第04章のサンプルでは、一部で record Product(...) という短い記法を使用しています。

record は主にデータを保持するためのクラスを簡潔に宣言できるJavaの仕組みで、Java 21で利用できます。 new Product("A01", "ノート", 120) と作成し、product.name() のように値を取得します。

第03章で学習した通常の class で書き換えても構いません。

注意:record はすべてのクラスの代わりになるわけではありません。業務で入力検証や状態変更が複雑な場合、通常のクラスが適することもあります。

まずは List<Product> が「商品オブジェクトを複数扱う」という意味であることを理解してください。

試すファイル:05_generics/Product.java と Main.java。


この節の独学チェック:07. ジェネリクスと型安全

確認問題: ListにIntegerを追加しようとすると、通常どうなりますか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

<>内のStringが何の型を表すか確認してください。

ヒント2

addに渡すIntegerがStringとして扱えるか考えてください。

ヒント3

ジェネリクスによる型検査はコンパイル時と実行時のどちらに行われるか確かめてください。

模範解答と理由

ジェネリクスの型制約によりコンパイルエラーです。Stringだけを要素として扱うためです。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: ListにInteger要素を追加する操作は通常コンパイルエラーである
  2. 1点: 型引数Stringは要素の型をStringに制約する

正答例: Listのadd(Integer)は通常コンパイルエラー。String以外を入れられないため。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: Integerは自動でStringに変換されるのでaddできる。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: <>内のStringが何の型を表すか確認してください。

08. Stream API の基本

Stream API は、複数のデータに対して条件抽出や変換、集計などの処理を組み立てる仕組みです。List そのものを変更する仕組みではなく、処理の結果として別の値やコレクションを得る使い方が基本です。

例えば List<Product> から100円以上の商品の名前だけを取り出すことができます。ここで言うストリームはファイルの入力ストリームとは別の概念です。

List<String> names = products.stream()
        .filter(p -> p.price() >= 100)
        .map(Product::name)
        .toList();

stream() はコレクションの要素を順に処理するための流れを作り、filter は条件を満たす要素に絞り、map は要素を別の値へ変換します。toList() で結果をリストとして得ます。

p -> p.price() >= 100 の矢印はラムダ式で、p を受け取って真偽値を返す短い処理を書いています。

Product::name はメソッド参照で、ここでは p -> p.name() に近い意味です。

流れの途中の filter や map だけでは、通常すぐにすべての要素が処理されるわけではありません。toList() や sum() などの終端操作で実際の処理が進みます。

試すファイル:06_stream/Main.java。100円以上の対象を200円以上に変更し、結果の違いを確認してください。

複雑なロジックは無理にStreamにせず、通常の for 文で分かりやすく書く判断も大切です。


理解を深める:Streamはfor文の動きを理解してから学ぶ

int total = prices.stream()
    .filter(p -> p >= 200)
    .mapToInt(Integer::intValue)
    .sum();
System.out.println(total); // 250

stream() は連続したデータ処理を組み立てます。filter は条件に合う要素を通し、mapToInt は整数値へ変換し、sum が合計します。

filter などの中間操作は通常、終端操作(ここでは sum)が呼ばれるまで処理が開始されません。

Streamが常に優れているわけではありません。 複雑な条件分岐や副作用を伴う更新はfor文の方が読みやすい場合があります。「短いコードを書くため」ではなく「処理の流れが分かりやすくなるか」で選んでください。

この節の独学チェック:08. Stream API の基本

確認問題: 価格一覧100,250,300から200以上をfilterすると、どの値が残りますか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

まず100、250、300の各値を200と比較してください。

ヒント2

filterの条件がtrueとなる要素だけを選んでください。

ヒント3

条件に一致する要素の元の順番も確認してください。

模範解答と理由

250と300が残ります。filterは条件に合う要素だけを次の処理へ流します。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: 200以上のfilter結果には250と300が残る
  2. 1点: 100は200未満なので除外される

正答例: 250と300。100は200未満なので除外される。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: 100、250、300がすべて残る。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: まず100、250、300の各値を200と比較してください。

図解:Stream APIの処理

Stream APIの処理

図の読み方:filterは要素の選別、mapは各要素の変換です。

09. 集計と並べ替え

数値データを合計するときは、Stream APIの mapToInt と sum を利用できます。次のコードは商品価格を整数として取り出し、すべて合計します。

int total = products.stream()
        .mapToInt(Product::price)
        .sum();

並び順を変えたい場合には sorted を利用できます。

例えば products.stream().sorted(Comparator.comparingInt(Product::price)).toList() で価格の昇順に並べた新しいリストを作れます。

Comparator を使う場合は import java.util.Comparator; が必要です。元の products リスト自体は、このコードだけでは並べ替えられません。

大量の金額や正確な小数計算が必要な業務では、int や double だけでは適切でない場合があります。ここでは仕組みを理解するために、小さな整数の価格を使っています。


理解を深める:for文からStreamへ

まず for 文で100円以上の金額だけを合計します。

List<Integer> prices = List.of(80, 100, 250);
int sum = 0;
for (int price : prices) {
    if (price >= 100) {
        sum += price;
    }
}
System.out.println(sum); // 350

次にStreamで同じ処理を書きます。

int sum = prices.stream()
    .filter(price -> price >= 100)
    .mapToInt(Integer::intValue)
    .sum();
System.out.println(sum); // 350

stream() はデータを順番に処理するための流れを作ります。filter は条件を満たす要素を残し、mapToInt は整数のストリームに変換し、sum は合計を計算します。

初心者はまずfor文で処理の流れを理解したあとに、Stream版へ書き換えてください。複雑な副作用を伴う操作をStreamへ押し込まないことも大切です。

演習: {90,120,220,40} から100以上の価格を取り出して件数2、合計340を、for文とStreamの双方で計算します。

この節の独学チェック:09. 集計と並べ替え

確認問題: 価格100,200,300の合計と降順の並びを答えてください。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

合計は3つの数値を足してください。

ヒント2

降順は値が大きいものから小さいものへ並べます。

ヒント3

合計を求める操作と並べ替える操作は異なることを確認してください。

模範解答と理由

合計は600、降順は300,200,100です。集計と並べ替えは別々の処理です。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: 100+200+300の合計は600である
  2. 1点: 降順は300、200、100の順である

正答例: 合計600、降順300、200、100。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: 合計600、昇順100、200、300を「降順」と答える。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: 合計は3つの数値を足してください。

10. null と Optional

null は参照先のオブジェクトがない状態を表します。例えば Map.get で存在しないキーを取得した場合などに現れます。

null に対してメソッドを呼び出すと NullPointerException が発生します。

Optional<T> は、値が存在する場合と存在しない場合を明示して扱うための型です。

Optional.ofNullable は値が null なら空のOptionalを作り、orElse(0) は値がないときの代わりとして0を使います。

ただし、「存在しない商品を0円とみなしてよいか」は業務仕様によります。実際の開発では、値がなければ例外にする、利用者へ通知するなど適切な仕様を決めてください。

試すファイル:07_optional/Main.java。A01 と X99 の表示を確認してください。Optional をすべての変数に使えば良いというものではありません。


この節の独学チェック:10. null と Optional

確認問題: String name=null; のとき name.length() を呼ぶとどうなりますか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

nameにStringインスタンスが代入されているか確認してください。

ヒント2

length()は何に対して呼び出すメソッドでしょうか。

ヒント3

nullに対してドット演算子でメソッドを呼ぶと起こる例外名を調べてください。

模範解答と理由

NullPointerExceptionになります。nullには参照先のStringオブジェクトがありません。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: name.length()の呼び出しでNullPointerExceptionが発生する
  2. 1点: nullはStringオブジェクトへの参照を持たず、インスタンスメソッドを呼べない

正答例: NullPointerException。nameがnullで参照先のStringがない。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: 長さ0の文字列として0が表示される。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: nameにStringインスタンスが代入されているか確認してください。

11. ファイルと文字コード

プログラムが終了してもデータを残しておきたいとき、ファイルを使用できます。例えば商品情報をテキストファイルに保存すれば、後から読み込んで処理できます。

Javaでは、ファイルの場所を表す Path と、読み書きを行う Files が利用できます。

Path path = Path.of("products.txt");
Files.write(path, List.of("A01,ノート,120"), StandardCharsets.UTF_8);

Path.of("products.txt") は相対パスです。相対パスは、実行時の作業ディレクトリを基準にします。

Eclipseから実行するときは、実行構成の作業ディレクトリがどこになっているかを確認しましょう。絶対パスは、たとえば C:\training\products.txt のように基準位置から指定する方法です。

WindowsのJava文字列でバックスラッシュを書く場合は \ とエスケープする必要があります。

StandardCharsets.UTF_8 は文字コードを指定しています。文字コードとは、文字をバイトの並びで保存するための規則です。文字コードが一致しないと日本語が文字化けする原因になります。

読み書きの双方でUTF-8を指定する習慣をつけましょう。

試すファイル:08_file/Main.java。実行後に products.txt ができたことを確認し、メモ帳などで開いてみてください。

もう一度実行すると、このサンプルでは既存ファイルの内容が上書きされることにも注意してください。


この節の独学チェック:11. ファイルと文字コード

確認問題: UTF-8で保存した「東京」を別の文字コードとして読み込むと何が起こりえますか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

文字はファイル内ではバイト列として保存されることを思い出してください。

ヒント2

書き出し時と読み込み時で文字コードが異なると、同じバイト列をどう解釈するでしょうか。

ヒント3

StandardCharsets.UTF_8を読み込みと書き込みの両方で指定する方法を確認してください。

模範解答と理由

文字化けが起こりえます。読み書きでUTF-8など同じ文字コードを明示する必要があります。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: UTF-8のバイト列を別の文字コードで解釈すると文字化けし得る
  2. 1点: 読み書きで一致する文字コード(本章ではUTF-8)を指定する

正答例: 文字化けすることがある。保存と読み込みの双方でUTF-8を指定する。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: UTF-8のファイルならどの文字コードで読んでも同じ文字になる。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: 文字はファイル内ではバイト列として保存されることを思い出してください。

12. IOException と try-with-resources

ファイルが存在しない、アクセス権限がない、ディスクに書き込めないなど、ファイル操作ではさまざまな問題が起こります。IOException はそのような入出力上の問題を表すチェック例外です。

チェック例外については、呼び出し元に伝える throws の宣言をするか、try/catch で処理するなどが必要です。

ファイルを読み込むために開いたリーダーなどは、使用後に閉じる必要があります。

try (BufferedReader reader = ...) というtry-with-resources構文を使うと、処理が終わったときに自動的に閉じることができます。

例外が起きた場合にも閉じる処理が行われるため、手作業で close() を忘れる危険が減ります。

try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
    String line;
    while ((line = reader.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    System.err.println("読み込みに失敗しました:" + e.getMessage());
}

このコードで readLine() は1行ずつ取り出し、終端では null を返します。

ファイルが非常に大きいとき、すべての行を一度にメモリへ読み込む readAllLines より、1行ずつ処理する方法が適している場合があります。

試すファイル:まず 08_file/Main.java を実行して products.txt を作ってから、同じ作業ディレクトリで 09_resource/Main.java を実行してください。

別のディレクトリで動かす場合は、ファイルをコピーするか作業ディレクトリを合わせます。


この節の独学チェック:12. IOException と try-with-resources

確認問題: Files.newBufferedReaderの読み取りをtry-with-resourcesに入れる理由は何ですか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

Readerはファイルなどの資源を管理するオブジェクトです。

ヒント2

tryの丸括弧内にReaderを置いたとき、tryが終わると何が起きるか確認してください。

ヒント3

処理途中で例外が起きた場合でもcloseが呼び出される理由を考えてください。

模範解答と理由

処理が正常終了しても例外終了しても、閉じる必要のあるReaderを自動でクローズするためです。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: try-with-resourcesに指定したReaderはスコープ終了時に自動的にcloseされる
  2. 1点: 例外が発生しても通常のスコープ終了時と同様にclose処理が行われる

正答例: tryを抜けるとReaderが自動クローズされ、途中で例外が起きても後片付けされる。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: 例外が起きた場合は必ず手作業でcloseしないと資源が閉じられない。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: Readerはファイルなどの資源を管理するオブジェクトです。

13. CSV形式の入力と、扱う範囲の注意

CSV は、複数の項目をカンマなどの区切り文字で並べたデータ形式です。例として A01,ノート,120 は、商品コード、商品名、価格の3項目を表すものとします。

String[] columns = line.split(",", -1);
int price = Integer.parseInt(columns[2].trim());

split(",", -1) はカンマで分割し、末尾の空項目も残します。trim() は前後の半角スペースなどを取り除きます。ただし、split で正しく扱えるのは単純なCSVだけです。

例えば商品名にカンマが含まれる場合や、ダブルクォーテーションで囲まれた改行を含む場合など、一般的なCSVの規則を正しく処理できません。実務ではCSVパーサーライブラリの利用を検討します。

ライブラリの導入はMavenとともに後の章で学習します。

不正な行があったときの振る舞いは仕様に依存します。エラー行だけ飛ばして処理を続ける方法も、全件取り込みを中止する方法もあり得ます。課題ではどちらの仕様なのかを最初に確認する習慣をつけてください。


理解を深める:CSVとファイル処理の落とし穴

Files.readAllLines(path, StandardCharsets.UTF_8) はUTF-8として読みます。指定しないと環境差で文字化けや読み取り失敗につながることがあります。

Path.of("products.csv") のような相対パスは、通常実行時の作業ディレクトリを基準にします。Javaソースがあるフォルダーとは限りません。

CSVは「カンマ区切り」だけでは済みません。"東京,本社" のように引用符で囲んだ欄や、引用符中の改行が存在します。split(",") はそのようなCSVを正しく解析できません。

教材の単純なCSV例は引用符や欄内改行のない限定形式として利用し、実務で一般的なCSVを扱うときは対応したパーサーを使います。

演習:結果を予想してから実行する

  1. Listの120円を1件削除すると合計はいくらになりますか。
  2. filter(p -> p >= 200) を p > 200 に変更すると、200円の商品はどう扱われますか。
  3. CSVファイルを別フォルダーに置いたとき、なぜ NoSuchFileException が起こり得るのでしょうか。
  4. 読み取り不可能なファイル、空行、数値欄に文字が入った行について、処理を継続するか停止するかを仕様として決めてください。

この節の独学チェック:13. CSV形式の入力と、扱う範囲の注意

確認問題: 単純なsplit(",")は「"東京,本店",100」を正しくCSV解析できますか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

"東京,本店"全体がCSVの1列になるのはなぜか確認してください。

ヒント2

split(",")が引用符を特別扱いするかどうか考えてください。

ヒント3

カンマで単純分割すると"東京と本店"の境界で何が起こるか確認してください。

模範解答と理由

正しく解析できません。split(",")は引用符の内側にあるカンマも分割位置として扱うため、"東京,本店"を一つの項目として維持できません。引用符やエスケープを扱う一般的なCSVには対応するパーサーが必要です。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: split(",")は引用符内のカンマも区切ってしまう
  2. 1点: 引用符やエスケープを扱う一般のCSVには対応したパーサーが必要

正答例: 正しく解析できない。引用符内のカンマも分割するのでCSV対応パーサーが必要。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: split(",")は自動で引用符を認識し、"東京,本店"を1列に保つ。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: "東京,本店"全体がCSVの1列になるのはなぜか確認してください。

14. 総合サンプル:商品CSV集計

第04章の内容をまとめて使う例を確認します。10_integrated のプログラムは、実行時の作業ディレクトリに products.csv がなければ練習用のファイルを生成し、そのファイルから商品情報を読み込みます。

そして、読み取れた商品の件数と価格合計を表示します。

処理の順序は、①ファイルを準備する、②行ごとに文字列を分割する、③項目数と価格を検証する、④ Product を作成して List<Product> に追加する、⑤Streamで価格を合計する、となっています。

不正な行はエラーメッセージを出して読み飛ばす仕様です。入力ファイルの読み書き自体に失敗した場合は、処理を中止してエラー内容を表示します。

最初の実行例(ファイルがまだない場合):

読込件数:3
価格合計:440円

学習手順:まず正常に実行します。次に products.csv に D04,クリップ,abc という行を追加し、価格の変換エラーが1行単位で表示されることを確認します。

さらに E05,テープ,-50 を追加し、価格の検証が働くことを確かめます。表示結果とCSVの内容が一致するか、一行ずつ追ってください。

重要:この教材は単純なCSVを前提とし、厳密なCSV解析や金額のオーバーフロー対策、ログ管理、テスト自動化は扱いません。実務では業務仕様に沿って別途設計する必要があります。


理解を深める:ファイルとCSVの異常系

Path path = Path.of("data", "prices.csv");
try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {
    String line;
    int lineNumber = 0;
    while ((line = reader.readLine()) != null) {
        lineNumber++;
        String[] columns = line.split(",", -1);
        if (columns.length != 2) {
            System.err.println(lineNumber + "行目: 列数が不正です");
            continue;
        }
        try {
            Integer.parseInt(columns[1]);
        } catch (NumberFormatException e) {
            System.err.println(lineNumber + "行目: 価格が整数ではありません");
        }
    }
} catch (IOException e) {
    System.err.println("ファイルの読み込みに失敗: " + e.getMessage());
}

上記はカンマを区切りとして単純に分割する学習用の例です。ダブルクォートで囲まれた値にカンマが含まれる一般的なCSVには対応しません。実務ではCSVの仕様を確かめ、必要なら専用ライブラリを利用します。

try (...) は処理が終わるとファイルを閉じるための構文です。StandardCharsets.UTF_8 で文字コードを明示します。

異常系演習: ファイルなし、空ファイル、列不足、整数以外の価格、正常な行をそれぞれ用意し、どの結果になるか表へ記録します。

学習者は例外を隠すのではなく、「処理を続けるケース」と「中断するケース」の判断理由も提出してください。

この節の独学チェック:14. 総合サンプル:商品CSV集計

確認問題: 商品CSVの1行が不正な数値だった場合、他の正常行を集計し続けるにはどこで例外を処理しますか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

CSV全体を読むループと、1行を処理する箇所を区別してください。

ヒント2

一行だけ失敗した場合に全行の処理を止めないtry/catchの位置を考えてください。

ヒント3

行番号と不正値を記録した後、次の行へ進む処理を確認してください。

模範解答と理由

行ごとの解析部分で不正値を捕捉し、行番号と原因を記録して、その行を除外し処理を継続します。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: 各行を解析する処理の内部で不正な数値変換を捕捉する
  2. 1点: 失敗した行を記録・除外し、正常な次の行の集計を継続する

正答例: 1行ずつの変換部分で例外を捕捉し、不正行だけ除外して次の行を集計する。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: ファイルを開く前だけcatchを置けば、不正行を飛ばして継続できる。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: CSV全体を読むループと、1行を処理する箇所を区別してください。

15. よくあるエラーと調べ方

cannot find symbol と表示される

クラス名や変数名、メソッド名が違っている可能性があります。List などのクラスを使うときは import java.util.List; のようなimport文が必要です。大文字・小文字も区別されます。

IndexOutOfBoundsException が発生する

List の存在しない番号にアクセスしている可能性があります。要素数が3ならインデックスは0、1、2です。size() の値そのものを get() に渡すと範囲外になります。

NullPointerException が発生する

参照が null の状態でメソッドなどを呼び出した可能性があります。たとえば Map.get("存在しないキー") が null を返していないかを確認します。

単に null チェックを増やすだけでなく、「値がないときの仕様」を考えましょう。

NoSuchFileException が発生する

ファイル名が間違っているか、作業ディレクトリが想定と違う可能性があります。

System.out.println(Path.of(".").toAbsolutePath().normalize()); で基準の場所を調べられます。

日本語が文字化けする

保存時と読み込み時の文字コードが一致しているか確認します。この章では両方に StandardCharsets.UTF_8 を指定します。ターミナル表示時の文字化けは、ターミナル側の文字コード設定が原因になる場合もあります。

例外を捕捉したのに原因が分からない

catch で何も表示していないと情報が失われます。まず例外の種類、起きた場所、発生前に何をしていたかを調べます。本番環境では個人情報や秘密情報をむやみにログに残さないことにも注意してください。


この節の独学チェック:15. よくあるエラーと調べ方

確認問題: NumberFormatExceptionが出たとき最初に何を調べますか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

NumberFormatExceptionは何の処理が原因で起きるか確認してください。

ヒント2

例外表示に含まれるファイル名・行番号を見つけてください。

ヒント3

数値変換を行った引数の実際の内容を調べてください。

模範解答と理由

例外が発生した行と、整数に変換しようとした元の文字列を調べます。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: 例外のスタックトレースから発生した行を確認する
  2. 1点: Integer.parseInt等に渡した元の文字列を確認する

正答例: 発生行と数値変換の元文字列を調べる。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: 例外が出たので、原因を調べずにcatchで無視する。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: NumberFormatExceptionは何の処理が原因で起きるか確認してください。

16. 理解度チェックと確認課題

教材を見ないで、次の質問に自分の言葉で答えてください。答えられない項目は該当する節を読み返し、サンプルの一部を変更して結果を見てください。

  1. コンパイルエラーと実行時例外は、どのタイミングで起こる問題でしょうか。
  2. try と catch は、それぞれ何を担当しますか。
  3. throw と throws の違いは何でしょうか。
  4. List・Set・Map は、それぞれどのような場合に使いますか。
  5. List<String> の String は何を表しますか。
  6. filter と map は、何をする操作でしょうか。
  7. Optional が空であることは、どのような意味でしょうか。
  8. UTF-8を明示するのはなぜでしょうか。
  9. 相対パスの基準になる場所は何でしょうか。
  10. なぜファイル操作に try-with-resources を使用するのでしょうか。

提出する演習は exercises/04_java_advanced/assignment.md にまとめています。解答例は講師用ファイルに分離しているため、演習を考えるまでは開かないでください。


この節の独学チェック:16. 理解度チェックと確認課題

確認問題: List/Map/例外/CSVに関する確認課題の採点は何に基づいて行いますか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

課題ごとに使うデータ構造と選択理由を書き出してください。

ヒント2

正常入力時の期待結果と実際の処理結果を並べてください。

ヒント3

不正値を与えた場合とCSVファイルの読み書き結果も確認してください。

模範解答と理由

選択したデータ構造の理由、正常入力の結果、不正値の取り扱い、ファイルの読み書き結果を各課題の期待値と照合します。

この節の自己採点基準(3点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: List/Map等のデータ構造を選択した根拠を確認する
  2. 1点: 正常入力に対する結果を期待値と比較する
  3. 1点: 不正入力の扱いとファイル入出力結果を期待値と比較する

正答例: データ構造の理由、正常系の結果、不正値対応と入出力結果を仕様の期待値に照合する。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: コードがコンパイルできたことだけをもって、すべての課題を満点にする。

合格条件:3/3点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: 課題ごとに使うデータ構造と選択理由を書き出してください。

17. まとめと第05章への接続

第04章では、複数のデータをまとめるコレクション、入力不備やファイル障害に対応する例外処理、要素の抽出と集計を行うStream API、そしてUTF-8のテキストファイルの読み書きを学びました。

これらを組み合わせれば、ファイルから商品一覧を取り込み、条件を確認したうえで集計する簡単なプログラムを作れます。

ただし、商品件数が増えたり、複数人が同時に更新したりする場合、ファイルを直接読み書きする方法では管理が難しくなります。次の第05章では、データを整理して保存・検索するためのデータベース(MySQL)とSQLを学習します。

第04章で作った商品情報を、データベースに保存して取り出す流れにつなげていきます。

学習内容の確認ポイント

Streamを学ぶ前に、同じ抽出処理をfor文で書いて結果を確認してください。CSVのサンプルは学習用の簡易形式です。引用符内のカンマ、改行、エスケープを含む本格的なCSVを安全に扱う場合は専用パーサーが必要です。

学習内容を振り返るための操作確認

この節は、本文の例題や演習が実行できないときに戻るための案内です。最初にファイルの場所と作業中のツールを確認し、コマンドを貼り付ける前に現在のフォルダーを確認してください。

実行する場所と順序

examples/04_java_advanced の各サンプルを節単位で実行します。ファイル入出力の節は入力ファイルの位置と実行時のカレントフォルダーを先に確認します。

成功・失敗の判断

例外処理では正常入力と異常入力、CSVでは正常な行と不正な行をそれぞれ試します。

途中で止まったとき

NoSuchFileException はファイル名だけでなく作業フォルダーから見た相対パスを確認します。

作業記録の書き方

  1. 利用環境(OS、Java、必要なツールのバージョン)を記録します。
  2. 実際に操作したフォルダー、実行コマンド、入力内容を記録します。
  3. 期待した結果と実際の結果を別々に書きます。失敗時にはエラーメッセージの全文を保管します。
  4. 修正を加えた場合は変更箇所を記録し、同じ手順で再確認します。
  5. 成功を確認できていなければ「未確認」と記載し、成功と推測して次へ進まないでください。

実際の入力、実行結果、原因の説明、演習の提出物がそろって初めて章の学習を完了とします。

この節の独学チェック:17. まとめと第05章への接続

確認問題: 第05章でCSVからDBに移ると、データの保存や検索はどう変わりますか。

取り組み方: 解答を読む前に自分の答えを記録してください。

ヒント1

CSVのデータを参照するとき何を読み込む必要があるか確認してください。

ヒント2

DBではデータの保存先と検索を行う仕組みがどこにあるか考えてください。

ヒント3

必要な商品だけを抽出・更新するときのSQLの役割を説明してください。

模範解答と理由

ファイル全体を読み込む方法から、DBにSQLを送って条件検索・更新する方法へ変わります。

この節の自己採点基準(2点満点)

採点条件(各1点。該当条件を満たした場合のみ加点)

  1. 1点: CSVファイルの読み書き中心からDBにデータを格納する方式に変わる
  2. 1点: DBにSQLを送って条件に合うデータを検索・更新できる

正答例: DBに格納し、SQLによって条件検索・更新する方式へ変わる。

部分点の例: 1つ目のみ正しく説明できた場合は1点、ほかの項目が不足していれば残りは0点。

誤答例: CSVからDBへ移っても、毎回全ファイルを読んで自分で検索しなければならない。

合格条件:2/2点。 不足した観点は本文の関連箇所に戻り、自分の言葉で再回答してください。

復習方法: CSVのデータを参照するとき何を読み込む必要があるか確認してください。