$30 off During Our Annual Pro Sale. View Details »

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
  2. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc

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

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

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

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

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

    • 実行時にErrorとExceptionを発生させて処理す る ◦ Error:プログラム上では対処不可のもの ◦ Exception:プログラム上で処理できる可能性 があるもの (補足)コンパイルエラー コンパイル時(実行前)に文法エラー等を検知 Javaでの話 8
  8. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc

    • 実行時にErrorとExceptionを発生させて処理す る ◦ Error:プログラム上では対処不可のもの ◦ Exception:プログラム上で処理できる可能性 があるもの Javaでの話 9
  9. Copyright (C) 2023 Toranoana Lab Inc. All Rights Reserved. #jjug_ccc_abc

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    • 例外処理は必須 • パターンマッチ/シールクラスの恩恵は例外処理で も受けられる ◦ 例外を大量に扱うのはキツイ・・・ • 例外処理は少ないに越したことはない まとめ 38