質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.50%

  • Java

    14060questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • 例外

    31questions

    例外(exception)とは、プログラムの処理実行中に発生する、通常の処理の続行を妨げる特殊な事象のことを呼びます。この「例外」が発生した場合に、現在の処理を中断し、変わりに別の処理を実行させる事を「例外処理」と呼びます。

Java 例外処理の運用ルール作っている?

解決済

回答 4

投稿

  • 評価
  • クリップ 1
  • VIEW 4,368

EKD

score 151

Javaの例外処理について、みなさまの開発チームでは運用ルールなどはありますか?
皆様の意見をお聞きしたいのは以下になります

1.事前にパラメータチェックするか
パラメータチェックせずに例外でチェックするか
ルールはありますか?

2.関数内でtry-catchするのか
呼び出し元へ例外を投げるのか
ルールはありますか?

3.例外を呼び出し元へ投げる場合には、発生した例外をそのまま投げますか?
それとも、独自の例外などに変換して投げますか?

4.throwsの記載には呼出元へcatchすることを強制する以外に意味があるのでしょうか?
テストしたところ、動作が変わらないように思えました
throwsには何を記載するようにしていますか?

5.例外処理に関して、有名なベストプラクティスなどはありますか?

<補足>
私はC言語出身の人間であったため、パラメータのチェックは事前に行い、
例外処理は基本は全て発生させないといった頭だったのですが、
色々調べてみますと、チェック処理が大量になるのを避けるため、
気軽に処理を呼出し、チェック処理は例外で一括化といった方法もあるようでした
そもそもJavaがそういった設計思想だったといった内容も見かけた気がします
事前チェックタイプの方が原因を特定しやすい気もしますが、
モダンなJavaの書き方ではないのでしょうか?

また、try-catchする場所に関しても、色々な意見があるようでして、
基本は全て呼び出し元へ投げ、一番上位層で処理するとか
基本は全て関数内でtry-catchし、処理できない場合のみ呼出元へ投げるとか

NumberFormatExceptionは事前チェックするけど、NullPointerExceptionはしないとか
FileNotFoundExceptionは呼出元へthrowするけど、IndexOutOfBoundsExceptionはcatchするとか、例外によってルールは異なるかもしれませんが、有名なルールや、ベストプラクティスといったものはあるのでしょうか?

もし、知っていましたら教えて頂けますと助かります

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+3

1~5の全ての答えに共通する考え方として、
モダンかどうかはわかりませんが、EFFECTIVE JAVA 第2版は、洗練されたコードが非常に多く、9章の例外は参考になると思います。

よくみる運用の基本的な考え方として、
2,3,4に関しては、特に例外をthrowさせる意図がないのであれば、throwせずその場で完結させます。
例外をthrowするにしても、独自の例外クラスを作成するにしても、そのようにする根拠が明確なときのみです。
このように運用しないと、独自の例外などが無駄に大量に増えることが多いです。

といっても、私もまだ経験が浅いので、ベストプラクティスがあるのであれば私も知りたいです。
が、そのベストプラクティスの参考になる基本的な考え方は、最初に紹介したEffective Javaが参考にされてつくられると思います。Javaプログラマの共通認識みたいなものなので。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/12 11:58

    ご回答ありがとうございます。参考になりました。
    EffectiveJavaですが、概要は把握しておりましたが、それを踏まえた上でのベストプラクティスなどがあるかと思い、質問させて頂きました

    キャンセル

+2

まず、Javaの例外には大きく分けて3種類あります。

  • 検査例外IOExceptionのような、「プログラマ側が処理することを強制される」例外です。
  • 非検査例外RuntimeExceptionのサブクラスです。ぬるぽやゼロ除算のような、「どこで起きるかわからない」例外に使われるクラスです。
  • エラーErrorのサブクラスです。処理系に異常があるとかメモリ不足とか、ほとんどの場合にユーザープログラムでどうしようもないものが投げられます。

基本的に、非検査例外はプログラムバグで出ることが多いですし、エラーはcatchしても処置不能なケースがほとんどですので、「これは必要」という理由がなければcatchすべきではありません。

  1. パラメータチェック vs 例外
    パラメータとして異常値が来ることがよくある(典型的には、ユーザー入力とかライブラリのpublicメソッド)ときには、例外を使わないほうがすっきりします(というより、通常処理と例外処理が混ざって無駄に複雑化します)。privateメソッドで、「プログラムバグでしか不正な値が来ない」場面なら、(非検査)例外を投げるほうが綺麗に書けます。

  2. 基本的には、そのメソッドを使う場面でどうするかを考えて例外は処理するかしないかを判断する必要があります。言語は違いますが、Ruby on Railsのデータベースメソッドには、「失敗すれば黙ってfalseを返す」saveと、「失敗時に例外を投げる」save!があります。

  3. これはプロジェクト次第とも言えます。

  4. 検査例外を起こしうるメソッドを呼ぶ場合、以下のどちらかをしないと、コンパイルすらできません。逆に、throws宣言をしておかないと、検査例外は投げられません。

  • 同じ例外、あるいは上位クラスの例外をthrowsとして宣言する
  • 内部でその例外をcatchする

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/12 11:59

    ご回答ありがとうございます。
    これら基本を踏まえた上で実際の現場などではどのようなルールで運用されているのか気になるところですが、大変参考になりました。

    キャンセル

+2

私の考えでは、方針として、ざっと

  • 事前に想定される例外で、回復可能なものは、「業務エラー」として、通常の画面に戻ってメッセージを出すなどします
  • 想定外のエラー(主にバグ)は、「システムエラー」として、最上位層で処理し、セッションを強制終了させます
  • 想定内でも、外部要因で発生するエラー(I/O,ネットワーク,DB起因でバグ以外)は、回復可能かどうかで「業務エラー」「システムエラー」に分けます
  • 例外を使わなくても処理できるものは例外処理を使わないようにします
  • 「業務エラー」の注意点として、ユーザーに見えてよい情報だけを通知するようにします

のような基本ルールを設けます。
これを踏まえて、個別に適用すると...

1

事前チェックとしてバリデーションを行います。
エラーは例外にせずに、戻り値として例えばValidationResultのような値を返して、その中でバリデーションエラーの詳細を持たせるようにします。
エラーハンドリング処理にジャンプさせる必要があれば、チェックが全て終わってからthrowします。

2

基本ルールに従います。
復元可能な例外は、関数内でキャッチして業務エラー処理に回します。

例えば、SQLExceptionでリトライ可能な種類なら、リトライさせるために内部でcatchします。

3

最上位層で処理するものは変換せずにthrowします。

ただし、検査例外などでその例外のthrows宣言が無いまたは宣言したくない場合は、変換することもあります。

4

まず大前提として、検査例外を上位にthrowする場合は必須ですね。

それ以外には、そのメソッド固有の想定される例外を記載します。

あとは前例に倣うのもアリです。
例えば、パーサーの処理ならたいてい、parse(String s) throws ParseExceptionとします。

5

そういうのは心当たりありませんが、
Odacchiさんの書かれているEffective Javaくらいでしょうか。

<補足>

NullPointerExceptionはライブラリーのバグでもない限り事前に防ぐことができるものとして、事前チェックして、発生した場合はシステムエラーにします。

NumberFormatExceptionも、想定される場合、たとえば数字以外も入力できてしまう値を数値に変換(parseIntなど)する場合は、事前チェックと完全に対応させるのが難しいし冗長になるので、catchで済ませる方が良い場合もあると思います。

FileNotFoundExceptionは、そのファイルがアプリの動作に必須のものなら「システムエラー」に、そうでなければ(回復可能なら)「業務エラー」にします。

あとはケースバイケースだと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/12 12:04

    ご回答ありがとうございます。
    業務エラーとシステムエラー参考になりました。勉強になります。

    キャンセル

checkベストアンサー

+1

maisumakunさんのおっしゃる、『検査例外とは「プログラマ側が処理することを強制される」例外である』という解釈、いろんなところで言われていますしEffective Javaにもそういう記述があると思いますが、それは誤った解釈かと考えています。

例えばNullPointerExceptionは検査例外ではありませんが、これだってプログラマ側が絶対にどこかの段階で処理する必要があります(しなければ、デスクトップアプリならクラッシュ、Webアプリなら真っ白な500画面です)。すべての例外はどこかの段階ではcatchされて適切な処理をしなければならないわけです。

ではどこに違いがあるか?

こう考えるべきです。検査例外とは「プログラマがどんなに注意深く呼び出しても防止できない例外」です。
防止しようがないということは必ず発生しうる→catchしていないなら確実にプログラミングミスだと断言できる→コンパイラがコンパイルエラーにする。
ということです。

非検査例外の代表、NullPointerExceptionしかりゼロ除算しかり、これらは(理論的には)注意深いプログラミングで避けられます。だから自身があればcatchを書く必要はありません。
検査例外の代表はどうでしょう、IOException、SQLException、InterruptedException、どれも起こるときは起こります。防ぎようがありません。だからcatchを書いていないのはおかしいです。

ここから、こういう指針が成り立ちます。

  • とにかく注意深くプログラミングし、防げる例外は防ぐ(これは質問文にもある通りです)
  • ただし注意にも漏れはあるので、プログラムの一番の呼び出し元ですべての例外をキャッチしログを取ったりエラー表示するなどの処理を書く
  • 検査例外は当然キャッチ。それも発生させうる呼び出しのできるだけ近くでキャッチ
  • 自分で作る例外は、呼び出す側で防止不可能なエラーかどうかを考え、防止可能ならRunTimeExceptionから派生させる

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/04/07 18:21

    JPCERT「ERR08-J. NullPointerException およびその親クラスの例外をキャッチしない」https://www.jpcert.or.jp/java-rules/err08-j.html というセキュリティ上の懸念もあり、「(NullPointerExceptionなどは)自身があればcatchを書く必要はない」という主張は少し気になります。

    キャンセル

  • 2016/04/08 14:39

    RuntimeExceptionを「いちばん外側で」キャッチするのは、エラーログ取得、最低限の後始末という正当な理由がありますので、そこまで否定するつもりはありません。

    キャンセル

  • 2016/04/12 12:02 編集

    ご回答ありがとうございます。
    大変参考になりました。また、yohhoyさん、maisumakunさんもコメントありがとうございます。非常に勉強になりました。
    今回は私の好みもあるかもしれませんが、yubaさんをベストアンサとさせて頂きます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

  • 解決済

    電卓プログラムの質問です

    javaにて電卓を作成しています。 以下が作成中のコードです。状態としては、コンソールに表示される段階のコードになります。 import java.io.BufferedRead

  • 受付中

    Javaの条件分岐 問題

    処理内容 引数1 計算方法(1足し算 2引き算 3掛け算 4割り算) 引数2 int xへ代入 引数3  int yへ代入 で実行しコンソールに計算結果を表示する。 エラー出力

  • 受付中

    Javaの質問です。テキストファイルのデータを上書き(部分的に削除)したいです。お力をお貸しください...

    初めて利用させていただきます。 現在私は、テキストファイルを用いるJavaの勉強をしております。 テキストファイルに、コンソールで入力した「name」「job」「sex」を

  • 解決済

    javaの例外について。

    javaの例外についてです。 import java.io.IOException; public class Main { public static void m

  • 受付中

    Junitでのthrowsについて

    Junitのメソッドではthrows句をしようして「throws Exception」と記述しますが、これは何のためにあるのでしょうか?

  • 解決済

    (Java)throwとthrowsの違いについて

    Javaを勉強している者です。 タイトルの通り、Java言語の例外処理で使われるthrowとthrowsの違いが よく分かりません。 どのような場合にthrowを使い、どのよ

  • 解決済

    例外処理を理解したい

    現在例外処理を勉強しています。 以下のコードで『IOException e』のところでエラーが出るのですが、なぜでしょうか。 「IOException の到達不可能な catc

  • 解決済

    CSVファイルから読み込んで郵便番号から住所を検索したい

    前提・実現したいこと 現在Javaでデータフォーマットの勉強をしています。 CSVファイルから郵便番号を読み込んで、一致する住所を表示するプログラムを書いたのですが、もっとこうすれ

同じタグがついた質問を見る

  • Java

    14060questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • 例外

    31questions

    例外(exception)とは、プログラムの処理実行中に発生する、通常の処理の続行を妨げる特殊な事象のことを呼びます。この「例外」が発生した場合に、現在の処理を中断し、変わりに別の処理を実行させる事を「例外処理」と呼びます。