Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Exceptionハンドリングの基本と新しい手法について【JJUG CCC 2023 fall】

Exceptionハンドリングの基本と新しい手法について【JJUG CCC 2023 fall】

2023/11/11 JJUG CCC 2023 Fall

https://ccc2023fall.java-users.jp/

河野裕隆
虎の穴ラボ株式会社

虎の穴ラボ株式会社

November 13, 2023
Tweet

More Decks by 虎の穴ラボ株式会社

Other Decks in Technology

Transcript

  1. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    例外処理の基本と新しい手法について
    虎の穴ラボ 河野 裕隆
    JJUG CCC 2023 Fall
    T O R A N O A N A L a b

    View full-size slide

  2. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    好きなもの
    ● VOCALOID(初音ミク)
    ● 謎解き、クイズ
    今期おすすめアニメ
    ● SHY
    ● 葬送のフリーレン
    自己紹介
    河野裕隆
    ● 2019/08 虎の穴ラボ入社
    ● 新規開発チーム
    ○ クリエイティア他
    虎の穴ラボへの入社理由
    ● スキルを高めあえる仲間がほしい
    ● ユーザーに近い仕事がしたい
    JJUG CCC登壇は1年ぶり2回目
    2

    View full-size slide

  3. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    ● Exceptionの基本
    ○ チェック例外
    ○ 非チェック例外
    ● ハンドリング手法
    ○ try-catch
    ○ Throw
    ● 他言語の対応
    ● パターンマッチングによるハンドリング
    話すこと
    3

    View full-size slide

  4. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    ● Step Upセッション
    ○ 初学者~を対象としています
    ● 例外について再整理したい人
    対象者
    4

    View full-size slide

  5. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    そもそもException(例外)って?
    5

    View full-size slide

  6. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    辞書的な意味:
    通例の原則にあてはまっていないこと
    一般的な話
    6
    プログラミングの文脈
    実行の継続を妨げる異常な事象
    (例)
    ● あるはずのファイルがない
    ● データベースにアクセスできない

    View full-size slide

  7. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    例外の役割
    7
    ● 大域脱出
    ○ 処理を中断して、ハンドリングしてくれる呼び出
    し元まで戻す
    ● 通常(正常時)の戻り値とは違う型の返却
    ○ 呼び出し元に正常時とは違うことをしてもらうと
    きに「例外の型」で判断してもらう

    View full-size slide

  8. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    ● 実行時にErrorとExceptionを発生させて処理す

    ○ Error:プログラム上では対処不可のもの
    ○ Exception:プログラム上で処理できる可能性
    があるもの
    (補足)コンパイルエラー
    コンパイル時(実行前)に文法エラー等を検知
    Javaでの話
    8

    View full-size slide

  9. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    ● 実行時にErrorとExceptionを発生させて処理す

    ○ Error:プログラム上では対処不可のもの
    ○ Exception:プログラム上で処理できる可能性
    があるもの
    Javaでの話
    9

    View full-size slide

  10. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    クラスの関係図
    Throwableを継承
    Exceptionは
    RuntimeExceptionと
    その他の例外にわかれる
    ErrorとExceptionとRuntimeException
    10

    View full-size slide

  11. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    チェック例外
    RuntimeExceptionを継承していない
    発生可能性と処理を明示する必要性
    非チェック例外
    RuntimeExceptionを継承している
    処理を明示する必要がない
    ErrorとExceptionとRuntimeException
    11

    View full-size slide

  12. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    チェック例外
    IOException、SQLExceptionなど
    主にファイルの有無や外部との疎通
    非チェック例外
    NullPointerException、
    IllegalArgumentExceptionなど
    実装時の考慮漏れやあえて例外に倒している箇所
    チェック例外/非チェック例外のサンプル
    12

    View full-size slide

  13. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    Exceptionが起きたら
    どうすればよいか
    13

    View full-size slide

  14. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    例外をそのまま呼び出し元に伝播させる
    Throw
    14
    try-catch
    例外の伝播を止めて、処理をする

    View full-size slide

  15. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    Throws
    // ユーザーサービスの実装
    public User findByName(String name) throws UserNotFoundException{
    return users.stream().filter((u) ->
    u.name().equals(name)).findFirst().orElseThrow(UserNotFoundException::ne
    w);
    }
    メソッドの定義のあとに「 throws 発生するクラス名」で上位に例外発生可能性を知らせるこ
    とができる
    15

    View full-size slide

  16. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    throw new UserNotFoundException();// 呼び出し元に例外を渡す
    try {
    // 例外が起こる可能性がある処理
    } catch (SampleException e) { // ハンドリングする例外
    throw new UserNotFoundException(e); // 例外のラッピング
    }
    try {
    // 例外が起こる可能性がある処理
    } catch (SampleException e) { // ハンドリングする例外
    throw e; // 例外の再Throw
    }
    Throw
    16

    View full-size slide

  17. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    UserService userService = new UserService();
    String searchUserName = "test";
    Optional user = userService.findByName(searchUserName);
    if(user.isEmpty()){
    throw new UserNotFoundException();
    }
    // ユーザーサービスの実装
    public Optional findByName(String name) {
    return users.stream().filter((u) -> u.name().equals(name)).findFirst();
    }
    Throw
    17

    View full-size slide

  18. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    try {
    // 例外が起こる可能性がある処理
    } catch (SampleException e) { // ハンドリングする例外
    // SampleExceptionの例外が起きた場合の処理
    } catch (Exception e) { // ハンドリングする例外
    // その他の例外が起きた場合の処理
    } finally {
    // 例外が起きても起きなくてもやって欲しい処理
    }
    try-catch 文法
    18

    View full-size slide

  19. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    UserService userService = new UserService();
    String searchUserName = "test";
    try {
    userService.findByName(searchUserName);
    } catch (UserNotFoundException e) {
    System.out.println("ユーザーが見つかりませんでした。 (" + searchUserName +
    ")");
    }
    // ユーザーサービスの実装
    public User findByName(String name) throws UserNotFoundException{
    return users.stream().filter((u) ->
    u.name().equals(name)).findFirst().orElseThrow(UserNotFoundException::ne
    w);
    }
    try-catch 実装例
    19

    View full-size slide

  20. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    throwsを書く
    1. チェック例外をthrowする場合
    2. チェック例外がthrows句にあるメソッド呼びcatchしない場合
    =>書かないとコンパイルエラー
    catchしてハンドリングする
    1. チェック例外がthrows句にあるメソッド呼び、catch伝播を止める場

    a. RuntimeExceptionでラップしてthrowする
    b. 適切に処理して正常系に戻す
    チェック例外でやらないといけないこと(非チェック例外でも可能)
    20

    View full-size slide

  21. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    - 適切に処理して正常系に戻す
    - その例外を開発者に通知する必要があるかを
    考える
    - 正常系に戻してしまうと問題の発覚が遅れる原
    因に
    - ログを出した上で正常に戻す等が必要
    catchしてハンドリングする上で注意が必要なこと
    21

    View full-size slide

  22. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    他言語ではどうしているのか
    22

    View full-size slide

  23. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    多値返却でカバー
    1. 複数の値を戻り値にできる
    2. panic/defer/recoverでtry-catchに近い動き
    a. panic:throwのような動き
    b. defer:finallyのような動き
    c. recover:catchのような動き
    (大域脱出は基本的にない)
    =>Javaの例外が乱用された結果の言語思想
    Go
    23

    View full-size slide

  24. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    回復可能なケース:Result
    =>パターンマッチでT型とE型で処理を分岐してハンド
    リング
    回復不可なケース:panic!(Javaで言うexitに近い)
    =>プログラムの強制終了に近いため、大域脱出とは
    異なる
    Rust
    24

    View full-size slide

  25. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    すべてが非チェック例外
    begin-rescueでtry-catchと同等の処理
    raiseでthrowと同等の処理
    Ruby
    25

    View full-size slide

  26. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    パターンマッチングによるハンドリング
    26

    View full-size slide

  27. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    Java21(LTS 2023/9~)
    switchで
    ● 型によるパターンマッチが使えるように
    ● シールクラスによる網羅担保ができるように
    =>catchの中で柔軟なハンドリングが可能に?
    パターンマッチ
    27

    View full-size slide

  28. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    UserService userService = new UserService();
    try {
    userService.createUser("test", 25);
    userService.findByName("test");
    return renderUserDetail();
    } catch (UserExceptionBase e) {
    return switch (e) {
    case UserNotFoundException ex -> renderNotFound();
    case UserNotUniqueException ex -> renderParamError();
    }
    }
    パターンマッチによる分岐
    28

    View full-size slide

  29. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    Java17(LTS 2021/9~)
    クラス/インターフェイスの継承先を制限
    =>親クラスに対する子クラスが自明になる
    シールクラス
    29

    View full-size slide

  30. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    // sealed で宣言し、permits で継承先を制限
    public abstract sealed class UserExceptionBase extends Exception permits
    UserNotFoundException, UserNotUniqueException {}
    // UserExceptionBaseを継承、finalで子クラスを制限
    public final class UserNotFoundException extends UserExceptionBase{}
    // UserExceptionBaseを継承、finalで子クラスを制限
    public final class UserNotUniqueException extends UserExceptionBase{}
    シールクラスの例外処理への応用
    30

    View full-size slide

  31. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    UserService userService = new UserService();
    try {
    userService.createUser("test", 25);
    userService.findByName("test");
    return renderUserDetail();
    } catch (UserExceptionBase e) {
    return switch (e) {
    case UserNotFoundException ex -> renderNotFound();
    case UserNotUniqueException ex -> renderParamError();
    }
    }
    パターンマッチによる分岐
    31

    View full-size slide

  32. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    ● catchを繰り返すより可読性が高い
    ● 例外が追加になった際に実装漏れが起きない
    ● ドメインごとにパッケージが切られていれば、わりと
    共通的にハンドリングできる
    メリット
    32

    View full-size slide

  33. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    ● 結局複雑度はそこまで変わらない
    ● ドメインごとに例外クラスを作る必要があり、クラス
    数が膨大になる
    ○ ドメインでわけないの不要な分岐をいたるところ
    にたくさん書くことになる
    デメリット
    33

    View full-size slide

  34. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    例外対応への考え方
    34

    View full-size slide

  35. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    ● 例外は例外である(当たり前ですが)
    ● 今回のコードでは不必要に例外を使っている
    ○ 処理結果用オブジェクトでハンドリングしたほう
    が良い場合が多い
    ● NullPointerException等もcatchするのではな
    く事前のチェック(validation)で対処したほうが良

    改めて例外とはなにか
    35

    View full-size slide

  36. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    SIerで作業していたころ
    ● コーディングが縦割りだったため、他のメンバーに
    意識してもらうために例外としておく
    例外への考え方の変化
    36

    View full-size slide

  37. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    現在(自社サービス)
    ● 極力発生させない、例外ではなくメッセージの伝播
    で対応する
    ○ 例外を例外時しか発生させないことで見通しを
    あげる
    コンウェイの法則
    組織構造がアーキテクチャに影響を与える
    例外への考え方の変化
    37

    View full-size slide

  38. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc
    ● 例外処理は必須
    ● パターンマッチ/シールクラスの恩恵は例外処理で
    も受けられる
    ○ 例外を大量に扱うのはキツイ・・・
    ● 例外処理は少ないに越したことはない
    まとめ
    38

    View full-size slide