0Pricing
Kotlin Academy · レッスン

カスタム例外クラスの作成

意味のあるメッセージとプロパティを持つ、ドメイン固有の例外を定義します。

「カスタム例外クラスの作成」はCoddyKit上の無料Kotlin Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはKotlin Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Kotlin Academyコースには全4レッスンが含まれています。

カスタム例外を使う理由

カスタム例外はドメイン上の意味を表します。呼び出し側は特定の例外だけを捕捉し、有用なメッセージを取得して、型に応じた異なる処理を実行できます。

最も簡単なカスタム例外

Exception(またはRuntimeExceptionのような特定のサブクラス)を継承し、スーパークラスのコンストラクターにメッセージを渡します。

class InvalidEmailException(message: String) : Exception(message)
fun main() {
    try {
        throw InvalidEmailException("missing @")
    } catch (e: InvalidEmailException) {
        println("caught: ${e.message}")
    }
}

プロパティを持つ例外

HTTPステータス、フィールド名、再試行回数などのフィールドを追加して、コンテキストを伝えます。

class HttpError(
    message: String,
    val statusCode: Int
) : Exception(message)
fun main() {
    try {
        throw HttpError("Not Found", 404)
    } catch (e: HttpError) {
        println("HTTP ${e.statusCode}: ${e.message}")
    }
}

原因を持つ例外

causeを渡して、元の例外をチェーン内に保持します。

class DatabaseError(message: String, cause: Throwable) : Exception(message, cause)
fun main() {
    try {
        try { error("connection refused") }
        catch (e: Throwable) { throw DatabaseError("query failed", e) }
    } catch (e: DatabaseError) {
        println("${e.message} (caused by: ${e.cause?.message})")
    }
}

検査例外と非検査例外

Kotlinでは、すべての例外が非検査例外として扱われるため、throws宣言は必要ありません。慣例としてRuntimeExceptionを継承します。

class ValidationException(field: String, message: String) :
    RuntimeException("[$field] $message")
fun main() {
    try {
        throw ValidationException("age", "must be positive")
    } catch (e: ValidationException) {
        println(e.message)
    }
}

ドメイン例外の階層

階層を構築すると、呼び出し側は一般的な処理には基底型を、特別なケースには特定のサブタイプを捕捉できます。

open class AppException(message: String) : RuntimeException(message)
class NotFoundException(what: String) : AppException("$what not found")
class UnauthorizedException : AppException("not authorized")
fun main() {
    val errors = listOf(NotFoundException("user"), UnauthorizedException())
    for (e in errors) {
        try { throw e }
        catch (e: AppException) { println("App error: ${e.message}") }
    }
}

sealed例外階層

エラー型の集合が限定されている場合は、sealed階層を使用します。呼び出し側で、すべてのバリエーションを網羅的に処理できます。

sealed class ApiError(message: String) : RuntimeException(message) {
    class Timeout : ApiError("timeout")
    class NotFound(val id: String) : ApiError("not found: $id")
    class ServerError(val status: Int) : ApiError("server returned $status")
}
fun describe(e: ApiError) = when (e) {
    is ApiError.Timeout -> "request timed out"
    is ApiError.NotFound -> "id ${e.id} missing"
    is ApiError.ServerError -> "5xx: ${e.status}"
}
fun main() {
    println(describe(ApiError.NotFound("user-42")))
}

命名規則

明確さを保つため、カスタム例外クラスの名前はExceptionまたはErrorで終わらせます。過去形または名詞を使用します(例:NotFound、InvalidInput)。

class InvalidInputException(msg: String) : RuntimeException(msg)
class UserNotFoundException(id: Int) : RuntimeException("user $id not found")
fun main() {
    try { throw UserNotFoundException(7) }
    catch (e: UserNotFoundException) { println(e.message) }
}

例外のドキュメント化

KDocの@throwsを使用して、関数がスローする可能性のある例外を記述します。

/**
 * @throws InvalidEmailException if the email is malformed
 */
fun validate(email: String) {
    if ("@" !in email) throw InvalidEmailException("missing @")
}
class InvalidEmailException(m: String) : RuntimeException(m)
fun main() {
    try { validate("nope") }
    catch (e: InvalidEmailException) { println(e.message) }
}

例外の過剰使用を避ける

例外は例外的な状況に使用します。空の入力や任意フィールドの欠落など、予想される結果には、nullableな戻り値、sealedな結果型、またはデフォルト値を使用してください。

fun findUser(id: Int): String? = if (id == 1) "Alice" else null
fun main() {
    val name = findUser(42) ?: "(unknown)"
    println(name) // (unknown), no exception
}

実践例

ステータスとボディを持つ、架空のAPIクライアント向けの現実的なカスタム例外です。

class ApiException(
    message: String,
    val statusCode: Int,
    val responseBody: String
) : RuntimeException(message)
fun main() {
    try {
        throw ApiException("Bad Request", 400, "{\"error\":\"invalid\"}")
    } catch (e: ApiException) {
        println("[${e.statusCode}] ${e.message}: ${e.responseBody}")
    }
}

クイックチェック

ドメイン固有のKotlin例外を定義するとき、最も一般的に使用される親クラスは何ですか。

まとめ

カスタム例外はドメイン上の意味を表します。RuntimeExceptionまたはExceptionを継承し、コンテキスト用のプロパティを追加し、原因を保持し、グループ化したcatchのために階層を構築します。エラー型が限定されている場合はsealed例外を使用し、エラーが予想される場合はnullable型やresult型を優先してください。

よくある質問

「カスタム例外クラスの作成」レッスンは無料ですか?

はい。「カスタム例外クラスの作成」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Kotlin Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Kotlin Academyコースには全4レッスンが含まれています。

「カスタム例外クラスの作成」で何を学びますか?

意味のあるメッセージとプロパティを持つ、ドメイン固有の例外を定義します。 ブラウザで直接実行するハンズオンコードでKotlin Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Kotlin Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのKotlin Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。

「カスタム例外クラスの作成」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このKotlin Academyレッスンでコードを書いて実行できますか?

はい。すべてのKotlin Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. 式としてのtry/catch/finally
  2. カスタム例外クラスの作成
  3. runCatchingとResult
  4. 例外の再スローとチェーン
← Kotlin Academyに戻る