「Java実践」タグアーカイブ

Java:IllegalArgumentExceptionの意味と例外設計のベストプラクティス

Javaアプリケーション開発では「想定外の入力」に対して適切にエラーを発生させ、プログラムの異常動作を防ぐことが重要です。その際によく使用される例外のひとつが IllegalArgumentException です。

本記事では、IllegalArgumentException の意味、発生するケース、使い方の例、そして例外設計のベストプラクティスまで徹底解説します。


IllegalArgumentExceptionとは?

IllegalArgumentException とは、

メソッドに不正な引数(値)が渡された場合にスローされる実行時例外(RuntimeException)

です。

例えば、年齢を受け取るメソッドに 負の値 が渡された場合など、
「引数の値が意味を成していない」状態で使われます。


なぜIllegalArgumentExceptionを使うのか?

✔ 不適切な入力を早期に検知
✔ 異常な状態を防ぎ、予測可能な動作を保証
✔ 開発者や利用側に明確なフィードバック

特に、ライブラリ・APIの開発時には重要です。
「どんな値が許容されるのか?」を明確にすることで利用者のミスを防げます。


IllegalArgumentExceptionの基本例

✅ 正の値のみ受け付けるメソッド例

チェックポイント

  • 条件式で検証

  • 明確なメッセージで何が悪いか伝える


Integerチューター:標準APIにも見る例

Java標準APIも積極的にこの例外を使っています。

例:Thread#setPriority(int priority)

Java公式の一貫性ある設計に従うことで、コード品質が向上します。


IllegalArgumentException vs 他の例外

例外使う場面
IllegalArgumentException引数の値が不正
NullPointerException引数がnull不可なのにnull
IllegalStateExceptionオブジェクトの状態が不正
IOExceptionI/O操作中の問題

ポイント

  • 値がおかしい→IllegalArgumentException

  • 状態がおかしい→IllegalStateException


ベストプラクティス:例外設計ガイド

✅ 1. 早めにチェックする(Fail Fast)

異常はできるだけ早く発見しましょう。

✅ 2. メッセージで原因を明示

悪い例(NG)

何が悪いのか分からない…

✅ 3. Javadocで事前に仕様を明記

APIの信頼性が向上します。

✅ 4. nullチェックはObjects.requireNonNullで簡潔に


ユースケース:バリデーションロジックの整理方法

例外処理が肥大化しないよう、専用バリデータクラスを作るアプローチも有効です。

利用例:


まとめ

ポイント内容
例外名IllegalArgumentException
意味不正な引数が渡された
目的予期しない動作を防ぐ
コツFail Fast、明確なメッセージ、仕様明記

良い例外設計はコードの信頼性・保守性を大きく高めます。
実務でも積極的に活用していきましょう!

JavaのGC(Garbage Collection)とは?仕組みと注意点

GCとは何か

Java で開発をしていると、よく耳にする「GC(Garbage Collection)」。
これは 不要になったオブジェクトを自動で回収してメモリを解放する仕組み のことです。C言語のように手動で free() を呼ぶ必要はなく、Java VM が裏側でメモリ管理を行います。

 

ざっくり構造・最近のGC

  • 世代別回収:Eden/Survivor(若世代)→ Old(老世代)

  • Minor GC:Edenが埋まったら短命オブジェクト中心に回収

  • Major/Full GC:Oldが逼迫、断片化、クラス/メタ領域逼迫などで広域回収

  • 既定GC:G1GC(Java 9+)。低停止要求は ZGC / Shenandoah も選択肢

主なトリガ

  • Eden満杯(Minor) / Old高水準(Major)

  • 巨大配列(Humongous)割当て(G1)

  • System.gc() 明示呼び出し

  • メタスペース/オフヒープ圧迫(DirectByteBuffer/JNI など)


“悪い例 → 良い例”で学ぶメモリ/GC対策

1) 無制限キャッシュ(静的Map地獄)

悪い例

良い例(上限+期限+統計)

ポイント:上限なしは必ずOldを膨らませる。キャッシュは 容量・期限・エビクションを設計。


2) リスナ/コールバック未解除

悪い例

良い例(ライフサイクルで必ず解除 / AutoCloseable化)

補足WeakReference リスナはイベント強度低下意図せぬ解放のリスク。基本は明示解除


3) ThreadLocal の放置(プールスレッドに張り付く)

悪い例

良い例(finallyで確実に除去)

ポイントスレッドプール=長寿命remove() を忘れると実質グローバル保持


4) System.gc() 乱用

悪い例

良い例


5) ラムダ/内部クラスが外側(巨大オブジェクト)をキャプチャ

悪い例

良い例(必要最小限のデータだけ渡す・static化)

ポイントキャプチャ=保持。意図せず大物を延命していないか疑う。


6) ループ内の大量一時オブジェクト

悪い例

良い例(StringBuilder再利用・ボクシング回避)


7) finalize/Cleaner頼み(遅延・不確実)

悪い例

良い例(確実な即時解放) 


8) クラスローダ・アプリ再デプロイ時のリーク

悪い例

良い例(クラスローダ境界を越える参照を断つ)

 

9) 巨大配列・Humongous割当ての長期保持(G1)

悪い例

良い例(分割・ストリーミング・寿命短縮)

ポイント:巨大ブロックは断片化回収コスト増の温床。


10) 無制限のキュー/バッファ

悪い例

良い例(有界+バックプレッシャ)


GCログ・計測の始め方(JDK 9+)

  • まずはコードの割当て削減 → その後にヒープ/GC調整

  • 監視:jcmd <pid> GC.heap_info / jstat -gc <pid> 1000

  • ボトルネック特定:JFR(Java Flight Recorder) で割当てホットスポットを把握

  • 必要なら ZGC/Shenandoah も評価(レイテンシ目標に応じて)


実務チェックリスト(配布推奨)

  1. System.gc() を禁止/抑制

  2. キャッシュ・キューは有界+期限

  3. ThreadLocal は finally で remove

  4. リスナ/コールバックは確実に解除(AutoCloseable化が効く)

  5. ループ内の一時オブジェクトを減らす(Builder再利用/ボクシング回避)

  6. 巨大配列は分割・短命化

  7. クラスローダ境界を跨ぐ静的参照禁止、Executor停止・ドライバ解除

  8. try-with-resourcesでオフヒープ即時解放

  9. GCログ/JFRで事実ベースに調整

  10. 目標停止時間(例:MaxGCPauseMillis)を定めて検証


まとめ

GCは“自動”でも“万能”ではありません。
「GCが働きやすいコード」(不要参照を残さない・波及して大物を掴ませない・ピークメモリを避ける)を心がけ、ログ/計測で改善ループを回すのが最短距離です。