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

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

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

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

Q&A

解決済

2回答

4733閲覧

Javaの例外処理のベストプラクティスについて(Java6)

退会済みユーザー

退会済みユーザー

総合スコア0

Java

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

0グッド

0クリップ

投稿2015/12/08 03:06

##Javaの例外処理のベストプラクティス
訳があって古いJavaでシステムを開発しています。例外処理に対して

java

1 2private void MainSubRoutine(){ 3 4 try{ 5 複数個の処理 6 } 7 catch(fooException e){} 8 catch (hogeException e){} 9 catch (Exception e) {} 10} 11

というコードを書いていたのですが

java

1 2private void MainSubRoutine(){ 3 4 try{ 5 単一の処理 6 } 7 catch(fooException e){} 8 try{ 9 単一の処理 10 } 11 catch (hogeException e){} 12 try{ 13 単一の処理 14 } 15 catch (Exception e) {} 16} 17

のようにする方が良いと教わったのですがキャッチする例外が多数重複している時に
冗長になる気がするのですがどちらの方式がいいのでしょうか。

上記の方で書いた理由はサーバ接続のエラーはレスポンスにエラーメッセージが返ってくるので例外処理で
それぞれのエラーメッセージを出力することで問題を切り分けられるに十分であると考えたからなのですが
下の書き方がどうもしっくりこないのです。もっといい方式はないでしょうか。

色々調べてみたのですが独自の例外クラスを作るほどの大袈裟な処理ではないので
標準エラークラスだけで何とかしようと思っています。

もし、単一の処理毎に例外処理の記述をするのであればたとえば、インターフェースを利用して

java

1 2private void ErrorThrow(IException e){ 3 4 try{ 5 throw e; 6 } 7 catch(fooException e){} 8 catch (hogeException e){} 9 catch (Exception e) {} 10 11} 12 13 private void MainSubRoutine(){ 14 15 try{ 16 単一の処理 17 } 18 catch (Exception e) { 19 ErrorThrow((hogeExeption) e) 20 } 21 try{ 22 単一の処理 23 } 24 catch (Exception e) { 25 ErrorThrow((fooExeption) e) 26 } 27}

のようにキャストを利用して投げるエラーを返る振り分けなどをするといった方法はどうでしょうか。

ご教授お願いいたします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

一般論としては後者の、「例外を投げ得る処理ごとにそれを捕まえる」が良いプラクティスです。
なぜ良いか。それはどこで何が失敗する可能性があるかをプログラマが完全に把握していてこそできることだからです。つまり大事なのは「一行ずつcatchする」ことではなくて「一行ずつの振る舞いを把握する」ことであります。

しかし前者の書き方、まとめてcatchをJavaは許容しています。というか、前者の書き方を可能にすることこそが「例外」というエラー通知システムです(最近流行のEitherやOption/Maybeなどといったエラー通知システムは前者のようなまとめてcatchをさせないシステムです)。

Javaは(もう少し言えば、この例外システムの源流であるC++は)なぜまとめてcatchを許容しているか? それはまさにtkow様のおっしゃるとおり、「冗長になるのを回避するため」です。

例えばSQLトランザクション内で何回もSQL命令を出します。どれが失敗してもトランザクションは失敗なので、トランザクションの外側でそれを一括catchしてリトライなりエラー表示なりすればよい、それを一箇所で書ける、冗長さをなくせたねというわけです。

まとめて言えば、各行で起こりうる失敗が明確化されていて(それはおそらく読み手のためにコメント付けされている必要があります)、かつ同種の失敗なので同種の扱いをするしかないのが明確なら一括catchで大いに結構となります。

最後に、質問文末で考案されている方式はあまり良いとは思いません。例外処理という言語処理系の基本的な仕組みをあまり独自なもので置き換えてしまうのは、読み手の理解を妨げる弊害が大きくなってきます。

投稿2015/12/08 03:23

yuba

総合スコア5568

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

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

退会済みユーザー

退会済みユーザー

2015/12/08 03:41

ありがとうございます。認識が合っていてよかったです。あと僕が上の方式を採用している理由はwhileの中にforがあるなどで階層的にtry~catchを書かなければいけない箇所があり,厳密に関数一回ごとのコールに対して処理を記述するとn(whileのループ回数)+n*m(forのループ回数)回例外判定を呼び出すのは処理的に無駄が多い気がしているのです。この辺りは内部で呼び出す回数を最適化してくれていたりするのでしょうか。計算コスト的にはある程度許容範囲ということになるのでしょうか。
yuba

2015/12/08 03:52

Javaのtryブロックにはほとんどオーバヘッドないんで、forループの内側に書くか外側に書くかでパフォーマンスに違いがあるかぜひ試してみてください。 C#だと同じような構文なのにtryに有意なオーバーヘッドがある、なんて違いがあったり。
yuba

2015/12/08 03:54

>liguofeng29さん あら、言っていることが正反対になってしまった… ちょっとまた調べてから。
退会済みユーザー

退会済みユーザー

2015/12/08 03:58

お二人ともありがとうございました。liguofeng29さんはパフォーマンスの検証記事まで探していただいてありがとうございます。 おかげさまで方針の目途がたちました。また何かあったらよろしくお願いいたします。
liguofeng29

2015/12/08 04:00

昼出てるので、戻ったら計測してみたいです。。。
yuba

2015/12/08 04:01

パフォーマンスの件なのですがこういう話もあって。 https://blog.katty.in/4119 これはループの外側に書くか内側に書くかの話でなくnull判定をifで書くかtry/catchで書くかの話なんですが、実際にnullが渡されない限りはtry/catchの方が早いんですよね。つまり例外が起こらなかった場合try/catchはほとんどオーバヘッドにならないというやつです。 で、これを前提に http://cs.hatenablog.jp/entry/2014/02/20/005212 こんな記事私書いてるんですが、実際計測していましてtry/finallyならオーバーヘッドなしでした。
Orlofsky

2015/12/08 04:06

昔、PL/SQLで1行ずつ厳格に例外を処理する、って規約で開発したことがありました。笑い コードが軽く5倍以上に膨らんで、バグは入り込み易いし、パフォーマンスは悪いし、大変でした。納品した後担当者から変更は大変だと悲鳴が聞こえて。。。 必要な例外はきちんと処理するのは漏らしてはなりませんが、過ぎたるは及ばざるがごとし。
退会済みユーザー

退会済みユーザー

2015/12/08 04:23 編集

yubaさんキャッチの処理は外部に処理を投げるので重たいのは知っていたのですがtryはほぼオーバーヘッドなしというのは初めて知りました。 検証してみないことには解らないものですね。liguofeng29さんのオーバーヘッドの件はIOstream関連とtryブロックの処理周りのポインタ移動が絡んでそうですね。Orlofskeyさんの意見は滅茶苦茶よくわかります。ベストプラクティスといっても色んな記事で意見が食い違うことも納得しました。
liguofeng29

2015/12/08 05:06

実際に時間計測をして見ましたが、(例外処理はなし) 私が参考したURLのようなパフォーマンス相違はかなったですが、 http://www.ibm.com/developerworks/jp/java/library/j-perf02104/ こちらで書いたように、例外を処理自体はコストがかかるのは間違いないかと。 なので、ループ内にするか外にするかはケースによるな個人的に思いました。 ループ処理10回のうち、例外の時点で処理を中止したい場合は、外側。 ループ処理10回のうち、例外発生しても処理を継続した場合は、内側。
guest

0

必ずこうでないといけないことはないですが、分けて書くことをお勧めします。

try{ 処理A(); 処理B(); 処理C(); ) cathch(例外A-1){} cathch(例外A-2){} cathch(例外C-1){} cathch(例外C-2){}

上記を分けた書いたほうが

  1. 例外が発生した場合にデバックが早くできると思います。
  2. ほかの人が見たときも処理Aに対してどういうハンドリングをしているのかがはっきり見えます。
try{ 処理A(); ) cathch(例外A-1){} cathch(例外A-2){} 処理B(); try{ 処理C(); ) cathch(例外C-1){} cathch(例外C-2){}

投稿2015/12/08 03:28

liguofeng29

総合スコア801

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

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

退会済みユーザー

退会済みユーザー

2015/12/08 03:45

やっぱり見やすさの問題ですよね。ソースコードの書き方って信頼性の要素を考えなきゃダメなのかなと思いました。自分で把握してるコードではサボるかもしれませんが人と共有するコードでは下のように書くようにします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問