Kotlinのrequireについて

採用はこちら

Kotlinにおける require は、関数や処理が成立するための「前提条件(precondition)」を明示的に検証するための標準関数です。

主に引数の妥当性チェックに使われますが、本質的には 「呼び出し側が守るべき契約」 をコードとして表現する仕組みです。

目次

requireの基本仕様

構文

require(condition)
require(condition) { "エラーメッセージ" }

挙動

  • condition == true
    → 何も起こらず、処理は継続される
  • condition == false
    IllegalArgumentException がスローされる

デフォルトの例外メッセージは "Failed requirement." です。

なぜ IllegalArgumentException なのか

require がスローする例外は常に IllegalArgumentException です。

これは「不正な引数・不正な前提条件で呼び出された」ことを意味します。

つまり require は、

この関数を呼ぶ側が、条件を満たしていない

という責任の所在を例外型によって明確にします。

エラーメッセージをラムダで渡す理由

require(age >= 0) { "age must be >= 0: $age" }

このラムダは 条件が false のときだけ評価されます。

  • 成功時はメッセージ生成が行われない
  • 文字列補間や重い処理を書いても無駄なコストが発生しない

これは Kotlin 標準ライブラリが requireinline 関数として実装しているためです。

requireの典型的な使用例

数値の範囲チェック

fun withdraw(amount: Int) {
    require(amount > 0) { "amount must be positive" }
}

文字列の妥当性チェック

fun registerUser(name: String) {
    require(name.isNotBlank()) { "name must not be blank" }
}

複数の前提条件を明示する

fun transfer(from: Account, to: Account, amount: Int) {
    require(amount > 0)
    require(from != to)
    require(from.balance >= amount)

    // 本処理
}

このように 関数の冒頭に前提条件をまとめる ことで、関数の仕様そのものがコードから読み取れるようになります。

requireNotNull について

null チェック専用の前提条件

fun printLength(text: String?) {
    val value = requireNotNull(text) { "text must not be null" }
    println(value.length)
}
  • null の場合は IllegalArgumentException
  • 戻り値は non-null 型 として扱える

これは Kotlin の Contract(契約) により、「ここ以降は null でない」という情報がコンパイラに伝わるためです。

requirecheckassert の違い

Kotlinには目的の異なる検証関数が用意されています。

関数役割例外意味
require前提条件の検証IllegalArgumentException呼び出し側の責任
check状態の検証IllegalStateException自身(クラス・処理)の責任
assertデバッグ用検証AssertionError開発時のみ

check の例(状態の不整合)

class Service {
    private var initialized = false

    fun init() {
        initialized = true
    }

    fun execute() {
        check(initialized) { "Service is not initialized" }
    }
}

assert についての注意点

  • JVMでは通常 無効
  • -ea(enable assertions)オプションを付けた場合のみ有効
  • 本番ロジックの前提条件チェックには向かない

requireを使うべきでないケース

ビジネスロジック上の分岐

// 不適切な例
require(age >= 18)

年齢制限のように 想定される条件分岐 は、例外ではなく通常の制御フローで扱う方が設計として自然です。

ユーザー入力の検証

  • フォーム入力
  • API リクエストのバリデーション

これらは「起こり得る失敗」であるため、Result や独自の検証結果オブジェクトで扱う方が保守性は高くなります
(ただし、例外を捕捉してレスポンスに変換する設計も一般的です)。

設計上の指針(実務向けまとめ)

  • 前提条件(呼び出し側の責任)require
  • 内部状態の整合性check
  • null を許可しない前提requireNotNull
  • require は関数の冒頭にまとめる
  • 仕様をコメントではなくコードで表現する

結論

require は単なる例外スローのショートカットではなく、

  • 関数の契約を明示する
  • 不正な呼び出しを即座に検出する
  • コード自体を仕様書にする

ための Kotlin らしい設計ツールです。

正しく使えば、バグの早期発見と可読性の向上を同時に実現できます。

以上、Kotlinのrequireについてでした。

最後までお読みいただき、ありがとうございました。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次