Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

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

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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