1. 通常の出金 (balance=1000, amount=300) → 700
  2. 残高不足 (balance=500, amount=1000) → -1
  3. ゼロ残高にゼロ出金 (balance=0, amount=0) → 0
  4. 残高ピッタリの全額出金 (balance=100, amount=100) → 0
  5. 1 円足りない (balance=999, amount=1000) → -1
  6. 大きい値でも正しく計算 (balance=1000000, amount=1) → 999999
コース一覧
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分

独自の例外を作る

「引数が不正です」では、何が起きたのか伝わらない

注文を受け付ける処理で、在庫が足りなかったとします。標準の IllegalArgumentException を投げても間違いではありません。ただ、受け取る側には「引数がおかしい」としか伝わりません。数量がマイナスなのか、在庫切れなのか、1 回の上限を超えたのか。区別する手がかりが型に残っていないのです。

すると、こういうコードが生まれます。

Java

} catch (IllegalArgumentException e) { if (e.getMessage().contains("在庫")) { // 入荷待ちの案内を出す } }

メッセージの文言を少し直しただけで壊れる分岐です。しかもコンパイラは何も警告してくれません。起きた出来事を、文字列ではなく型で表せば、この問題は消えます。

業務の言葉でクラスを 1 つ作る

RuntimeException を継承したクラスを 1 つ書くだけで、自分専用の例外ができます。

Java

public class OutOfStockException extends RuntimeException { public OutOfStockException(String message) { super(message); } }

大事なのは super(message) です。ここで親にメッセージを渡さないと、あとで e.getMessage() を見たときに null が返ってきて、原因が何ひとつ分からなくなります。

投げる側は、業務のルールに違反した場所でそのまま throw します。

Java

if (requested > stock) { throw new OutOfStockException("在庫不足 商品=" + itemId + " 残り=" + stock); }

受け取る側は、専用の型で捕まえられます。

Java

try { acceptOrder(itemId, requested); } catch (OutOfStockException e) { System.out.println("入荷までお待ちください"); }

型は catch が読むもの、メッセージは人がログで読むものです。役割を分けておくと、どちらも短く保てます。名前は OutOfStockException のように業務で使っている言葉から取ってください。DataException のような一般名を付けると、せっかく型で分けた意味が薄れます。

Exception と RuntimeException、どちらを継承するか

判断の基準は「呼び出し側に対処を強制したいかどうか」の一点です。

Exception を継承すると検査例外になり、この例外を投げるメソッドには throws の宣言が必要になります。その呼び出し元にも、さらにその呼び出し元にも伝染していきます。強制したい場面では有効ですが、たいていは重すぎます。

RuntimeException を継承すれば非検査例外になり、宣言なしで投げられます。Spring などのフレームワークもほぼこちらで統一しています。迷ったら RuntimeException を選んでおけば大きく外しません。

原因になった例外も一緒に運ぶ

外部システムの呼び出しで起きた例外を、自分の業務例外に包み直すことがあります。このとき元の例外を捨てると、本当の原因がログから消えます。

Java

public OutOfStockException(String message, Throwable cause) { super(message, cause); }

このコンストラクタを足しておくと、new OutOfStockException("在庫照会に失敗", e) のように元の例外を持たせられます。スタックトレースに両方が並ぶので、追いかけるのが一気に楽になります。

要件

  1. InsufficientFundsException という名前のカスタム例外クラスを Solution の内部 (static class) として定義すること
  2. InsufficientFundsException は RuntimeException を継承し、String message を受け取るコンストラクタで super(message) を呼ぶこと
  3. withdraw メソッドの中で、amount > balance のときに InsufficientFundsException を throw し、同じメソッド内の catch で受けて -1 を返すこと

入出力例

withdraw(1000, 300) → 700 withdraw(500, 1000) → -1 withdraw(0, 0) → 0 withdraw(100, 100) → 0 withdraw(999, 1000) → -1 withdraw(1000000, 1) → 999999

ヒント

内部クラスとして `static class InsufficientFundsException extends RuntimeException { ... }` を `Solution` の中に書くと、別ファイルを用意せずに 1 ファイルで完結します

`if (amount > balance) throw new InsufficientFundsException("...")` のように、不等号は `>` を使います。`>=` にすると残高ピッタリの全額出金で誤って `-1` を返してしまうので注意してください

`try { ... } catch (InsufficientFundsException e) { return -1; }` の構造で囲み、`try` の中で正常な出金額 `balance - amount` を `return` する形にすると、本文どおりの実装になります

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

関連レッスン

  • try-with-resources

    AutoCloseable なリソースを安全に扱う try-with-resources 構文を学び、リソースの自動クローズを体験しよう。

  • finally ブロック

    Java の `try` 文で必ず実行される `finally` ブロックの役割をリソース解放や後始末の観点から学び、整数除算の結果を `,end` 付きで返すメソッドを実装してみよう。

  • 例外処理 まとめクイズ

    例外処理 (try-catch / 複数 catch / throws / カスタム例外 / try-with-resources / finally) の総まとめ。検査例外と非検査例外、catch の順序、finally で return など実務頻出のポイントを 4 択クイズで確認する。

  • Stream を作る

    Java の Stream API を学ぶ最初のステップとして、配列やコレクションから Stream を生成し、count などのターミナル操作で要素数を取得するコードを書いてみよう。

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

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

  • 引数位置引数=順番で渡す。
  • 処理計算や代入を表す長方形
  • クラスデータと振る舞いを束ねる単位
  • 継承親クラスの機能を子クラスへ引き継ぐ仕組み
  • 判断YES/NO 分岐を表す菱形
  • メソッドクラスに属する関数
  • コンストラクタインスタンス生成時の初期化処理
  • スタック後入れ先出し(LIFO)のデータ構造
main.java
学習モード
エディタを読み込んでいます

メモ

独自の例外を作る

⌘S で保存