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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Java

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

例外

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

Q&A

解決済

4回答

12155閲覧

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

EKD

総合スコア161

Java

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

例外

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

2グッド

2クリップ

投稿2016/04/07 04:23

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

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

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

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

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

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

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

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

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

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

A-pZ, yohhoy👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

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

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

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

  1. パラメータチェック vs 例外

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

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

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

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

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

投稿2016/04/07 04:50

maisumakun

総合スコア145183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

EKD

2016/04/12 02:59

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

0

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

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

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

投稿2016/04/07 04:39

編集2016/04/07 04:46
Odacchi

総合スコア907

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

EKD

2016/04/12 02:58

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

0

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

  • 事前に想定される例外で、回復可能なものは、「業務エラー」として、通常の画面に戻ってメッセージを出すなどします
  • 想定外のエラー(主にバグ)は、「システムエラー」として、最上位層で処理し、セッションを強制終了させます
  • 想定内でも、外部要因で発生するエラー(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/08 05:27

argius

総合スコア9388

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

EKD

2016/04/12 03:04

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

0

ベストアンサー

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

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

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

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

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

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

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

投稿2016/04/07 08:12

yuba

総合スコア5568

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yohhoy

2016/04/07 09:21

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

2016/04/08 05:39

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

2016/04/12 03:04 編集

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問