なぜJavaの人々は頻繁に例外を黙って消費するのですか?


81

これまで本格的なJavaコーディングを行ったことはありませんでしたが、既存のスキル(DelphiとC#)に基づいて構文、ライブラリ、概念を学びました。私がほとんど理解していないことの1つは、次のprintStackTraceようにした後、例外を黙って消費するコードをたくさん見たことです。

    public void process() {
        try {
            System.out.println("test");
        } catch(Exception e) {
            e.printStackTrace();
        }
    }

私が遭遇したほとんどすべてのJavaの記事とプロジェクトには、このようなコードがあります。私の知識に基づくと、これは非常に悪いことです。ほとんどの場合、例外は次のように外部コンテキストに転送されます。

    public void process() {
        try {
            System.out.println("test");
        } catch(Exception e) {
            e.printStackTrace();
            throw new AssertionError(e);
        }
    }

ほとんどの場合、例外は、基盤となるフレームワーク(Java Swingなど)に属する最も外側のループで処理されるはずです。Javaの世界でこのようにコーディングするのが標準のように見えるのはなぜですか?困惑しています。

私の経歴に基づいて、printStackTraceを完全に削除したいと思います。私は単に未処理の別名RuntimeException(または、さらに良いAssertionError)として再スローし、それを最も適切な場所であるフレームワークの最も外側のループでキャッチしてログに記録します。

    public void process() {
        try {
            System.out.println("test");
        } catch(Exception e) {
            throw new AssertionError(e);
        }
    }

56
スタックトレースが出力されるとき、それは本当に静かではないと思います:)
willcodejavaforfood 2009年

13
Isaac Wallerを引用してもいいですか「しかし、あなたのプログラムは終了せず、続行します。おそらく未定義の状態です」

15
@ willcodejavaforfood、あなたのコメントは非常に多くの票を獲得し、それは典型的なJavaの考え方について私をさらに困惑させます。
日本酒

13
@ willcodejavaforfood-発信者の観点からは無音です。発信者は、何かが起こったことを知りません。さて、それが意図されているのであれば、それは問題ありませんが、一般的に、それは悪いニュースです。また、アプレットで何が起こるかを考えてください。ユーザーには出力が表示されません(Javaコンソールが開いている場合を除きます)。さて、これ以上アプレットを使用する人は誰もいません;)servletmについても同様ですが、エンドユーザーは何が起こったのかを知りません。ログに隠されるだけです。
スコットスタンチフィールド

4
Javaでの例外スローは非常に一般的であるため、ほとんどのJavaコーダーはそれらを無視します。これは、正しいエラーキャッチを行うと、さらに多くのコードを作成する必要があるためです。
Trevor Boyd Smith

回答:


203

私はいつも考えていました、それは次のシナリオに似ています:

「男が撃たれる。

彼は息を止め、バスに乗るのに十分な力を持っています。

10マイル後、男はバスを降り、数ブロック歩いて死んだ。」

警察が体に着いたとき、彼らは今起こったことの手がかりを持っていません。彼らは最終的に持っているかもしれませんが、それははるかに困難です。

より良いのは:

「男は撃たれ、彼は即座に死にます、そして、体は殺人がちょうど起こったところに正確にあります。」

警察が到着すると、すべての証拠が整っています。

システムに障害が発生した場合は、迅速障害を発生させることをお勧めします

質問への対処:

  1. 無知。
      +
  2. 怠惰

編集:

もちろん、キャッチセクションは便利です。

例外を除いて何かを行うことができる場合は、それを行う必要があります。

おそらくそれは与えられたコードの例外ではなく、おそらくそれは予想されるものです(そして私のアナロジーでは防弾ジャケットのようなもので、男はそもそもショットを待っていました)。

そして、はい、キャッチは抽象化に適切な例外スローするために使用できます


2
例外を飲み込むことは失敗ではありません、速く失敗することを気にしないでください。一方、メソッドコントラクトに数字の文字列であるパラメーターがあり、それを整数に解析している場合は、ParseExceptionを飲み込むことができます。特定の機能を作成している場合は、失敗したその機能のカスタム例外を定義してから、例外をキャッチしてカスタム例外をスローします(元の例外を引数として)。その後、意味のある動作が発生する可能性のある場所(ユーザーへの表示、電子メールの送信、ログ記録、このサーバースレッドの終了など)にすばやく失敗する可能性があります。
JeeBee 2009年

21
ちょっと待ってください...最初に笑うのをやめる必要があります...わかりました...それは私がこれまでに見た質問に対するこれまでで最も面白い答えでした。それは非常に重要な意味を持ちます。処理のために例外を「チェーンの上位」に渡すことは非常に役立つ場合がありますが、少なくとも最初に例外をキャッチしてから渡すことをお勧めします。そうすれば、いくつかの有用な情報を含めることができます。
ウィル氏

例外はエラーではありません。例外を投げるのは、男が撃たれ、メモに事件の詳細を記入し、最寄りの殺人隊に飛ぶように訓練された伝書鳩にそれを添付することです。
ジェリコ2009年

13
@オスカー、できれば+100。不十分な例外処理は、怠惰ではなく、IGNORANCEとMALICEの結果です。怠惰=可能な限り少ない労力。例外処理の愚かさは、それを減らすのではなく、より多くの作業を引き起こします...もちろん、それは通常、他の誰かのためにより多くの作業を引き起こします。それが「怠惰」に見える理由です。
James Schek 2009年

1
私はあなたのポイントオスカーを見ますが、例外を処理するか、それをログに記録することはすべて、例外が発生したことを示しています。チェーンの最後までスローすると、最終的にどのメソッドが例外を呼び出したかがわかります。
マウロ

33

通常、これは、IDEが、問題のあるコードをその例外処理でtry-catchブロックにラップする便利な「クイックフィックス」を提供しているためです。アイデアはあなたが実際に何かをするということですが、怠惰な開発者はしません。

これは間違いなく悪い形です。


2
同意しました。与えられた例は、Eclipseのデフォルトのクイックフィックスのように見えますが、// FIXME:コメントが削除されています。
JeeBee 2009年

2
さて、あなたは「これは間違いなく悪い形です」と言いました、そして私は100%同意します。しかし、他のいくつかの回答やコメントは、Java開発者の非常に大きな部分(私は信じています)の背後にある哲学に非常に興味をそそられます。
日本酒

4
Eclipseがそこで劇的なことをしてくれることを本当に望んでいます。たとえば、e.printStackTrace(); System.exit(1);
Adam Jaskiewicz 2009年

4
IDE設定を変更して、RuntimeExceptionとして再スローするキャッチボディを生成しました。これははるかに優れたデフォルトです。
Esko Luontola 2009年

6
例外が発生しないことが確実な場合は、通常、意図を文書化する方法として、RuntimeExceptionではなくAssertionErrorをスローします。
Esko Luontola

20

これは古典的なストローマンの議論です。 printStackTrace()デバッグ支援です。あなたがブログや雑誌でそれを見た場合はライターがポイントを示すに興味があったので、それはだった他の例外処理よりを。本番コードでそれを見た場合、そのコードの開発者は無知または怠惰であり、それ以上のものではありませんでした。これは、「Javaの世界」での一般的な慣行の例として取り上げるべきではありません。


1
それで、プロプログラマーが本番ではなくブログや雑誌に悪いコードを書いても大丈夫ですか?idはむしろ本番環境で悪いコードを書きます。本当に賢い人がprintStackTraceを使用している場合、彼は人々にそれを使用するように説得します。例外コードが8文字長いことは理解していますが、...
IAdapter 2009年

8
@ABCDE:私はまったく同意しません。あなたはむしろ本番環境で悪いコードを書きたいですか?それが機能するはずのコードです!ブログや雑誌の記事がポイントを説明することになっています。エラー処理が重要でない場合は、混乱している可能性があります。多くのライターは、記事で大幅に簡略化されたエラー処理を使用するか、まったく使用しません。これは従うべき例ではありません。
トカゲのビル

19
  1. Javaでは、すべての例外を明示的に処理する必要があります。あなたのコードの呼び出しが宣言されていること方法がFooExceptionとBarExceptionあなたのコードをスローする場合はMUSTのこれらの例外をハンドル(またはスロー)。これに対する唯一の例外は、忍者のように沈黙しているRuntimeExceptionです
  2. 多くのプログラマーは怠け者であり(私自身も含まれます)、スタックトレースを印刷するのは非常に簡単です。

7
しかし、プログラムは終了せず、続行します。おそらく未定義の状態です。
Isaac Waller

5
例外のタイプがわかっている場合、状態はどのように未定義ですか?それはかわいい引用ですが、通常、プログラムは続行でき、続行する必要があります。例外のためにアプリケーション全体がクラッシュすることは望ましくありません。ユーザーに伝えて、もう一度何でもするように依頼してください。
GreenieMeanie 2009年

2
例外が最外部レベルで適切に処理されれば、アプリケーションはクラッシュしません。
日本酒

2
例外の少なくとも半分は「RuntimeExceptions」であり、1つしかないように聞こえます。そして、それはサイレントではなく、キャッチされていないRutimeExceptionはスタックトレースを出力し、プログラムをクラッシュさせます。
ビルK

@greenieMeanie一般に、開発では、わずかな問題でハードにクラッシュさせたいと考えています。開発者が電話を台無しにして逃げないようにしてください。何も許さないでください。一方、あなたがそれを出荷するとき、あなたは反対に行きたいです。すべての例外を目に見えない形で記録し、回復して続行するために最善を尽くします(Javaは非常に優れています)。
ビルK

12

これが行われる理由は2つあることがよくあります

  1. プログラマーは怠け者でした
  2. プログラマーは、そこのコンポーネントへのエントリポイントを(正しくまたは誤って)保護したかった

これはJavaに限った現象ではないと思います。このようなコーディングは、C#やVB.Netでもよく見られます。

表面的にはかなり衝撃的でひどいように見えます。しかし、実際にはそれは新しいことではありません。これは、エラーコードの戻り値と例外を使用するC ++アプリケーションで常に発生します。ただし、致命的な可能性のある戻り値を無視しても、voidを返す関数を呼び出すのと実際には何の違いも見られないという違いがあります。

Foo* pFoo = ...;
pFoo->SomeMethod(); // Void or swallowing errors, who knows?

このコードは見た目は良くなりますが、SomeMethod()がHResultを返すと言った場合、意味的には例外を飲み込むのと同じです。


3
特にこの質問では、理由1が理由2よりもはるかに一般的だと思います
マットb

2
@matt b、同意しました。怠惰は私が最近修正したバグのかなりの部分に責任があります。
JaredPar 2009年

エラーコードを無視することは、非常に迅速であり、ボイラープレートコードの使用量がはるかに少なくなります。
gbjbaanb 2009年

11

チェックされた例外のため失敗した実験があります

(多分printStackTrace()が本当の問題ですか?:)


17
それらは失敗した実験ではありません。実は好きです!他の回答で指摘されているように、プログラマーは怠惰になり、エラーケースを無視する傾向があります。チェックされた例外はそれらに対処することを強制するので、全体的に優れたコードが得られます。(プログラマーがそれらを黙って無視していない場合)。また、怠け者でなくても、コンパイラがそうするように指示するので、重要な例外をキャッチすることを忘れることはできません...
Malax 2009年

5
チェックされた例外はいくつかの理由で失敗です:それらのいくつかをチェックしてくださいmindview.net/Etc/Discussions/CheckedExceptions
dfa

2
+1はこれ以上同意できませんでした。チェックされた例外はコードの安全性を低下させることが多く、これはその方法の一例です。
cletus 2009年

2
チェックされた例外は間違いなく完璧ではありませんが、計画どおりに進まないことがあるという現実に直面することを余儀なくされます。チェックされていない例外は、私たちが何も問題がない完璧な世界に住んでいるふりをしようとしているだけです
mcjabberz 2009

2
@Peter Lawrey:チェックされた例外は失敗です。なぜなら、驚くべきSwingフレームワークに付属しているような非常に賢い人々がそれらを突いて、それらの使用を拒否するからです。そして、JoshuaBlochやSpringフレームワークの背後にいる人々のような人々が「それらを正しく使用する方法を知らない」ことを私は非常に疑っています。確かに、チェックされた例外を正しく処理できます。本当の失敗は、誰かが、どこかで、投げることは容認できる習慣だと思ったことです。
SyntaxT3rr0r 2010年

6

この種の緩いエラー処理動作がJavaプログラマーにとって基本的なものであることを暗示する口調に少し憤慨していると言わざるを得ません。確かに、Javaプログラマーは、他のすべてのプログラマーと同じように怠惰になる可能性があり、Javaは人気のある言語であるため、例外を飲み込むコードがたくさんあることでしょう。

また、他の場所で指摘されているように、個人的には問題はありませんが、Javaが強制的にチェック例外を宣言することには理解できるフラストレーションがあります。

私が問題にしているのは、コンテキストを気にせずにWeb上の多数の記事やコードスニペットをざっと読んでいることだと思います。真実は、特定のAPIがどのように機能するか、または何かを開始する方法を説明しようとする技術記事を書いているとき、コードのいくつかの側面をスキップする可能性が非常に高いです-直接ではないエラー処理特に、シナリオ例で例外が発生する可能性が低い場合は、デモンストレーションしている内容に関連するものが廃棄の候補になる可能性があります。

その性質の記事を書く人々は、合理的な信号対雑音比を維持する必要があり、かなり公平に、それはあなたが開発している言語についていくつかの基本を知っていると仮定しなければならないことを意味すると思います。エラーに適切に対処する方法、および他の多くのもの。記事に出くわし、適切なエラーチェックが不足していることに気付いた場合は、それで問題ありません。これらのアイデアを本番コードに組み込むとき(もちろん、正確なコード自体は決してありませんよね?)、作者が賢明に省略したすべてのビットとボブを、最も適切な方法で処理することを確認してください。あなたが開発しているものに適しています。

私は、そのような問題に戻ることなく簡単に説明する非常に高レベルの紹介記事に問題がありますが、エラー処理に関するJavaプログラマーの特定の「考え方」がないことに注意してください。私はあなたの愛するC#プログラマーの多くが彼らのすべての問題に対処することを気にしないことも知っています。


しかし、を使用して高レベルの記事を書くことtry {...} catch (IOException e) {}は明らかに愚かです(そしてTODOは役に立ちません)。それは確かに多くの初心者を同じことをするように誤解させるでしょう。さらに、ほとんどの場合正しい、よりも書くほうがはるかに多いthrows IOExceptionです。たぶん、論文ごとに一度、それは不可能であり、それから書くことthrow wrap(e)(定義するのに退屈しないでwrap)は良い解決策です。私がJavaに最初に傾倒したことの一つは、黙って飲み込むことはひどいことであり、私は細心の注意を払っているので、一時的にさえそれをしません(クラッシュさえ長期的にははるかに良いです)。
maaartinus 2017

5

System.out printまたはe.printStackTrace()-これは通常、System.outの使用が危険信号であり、誰かがわざわざ勤勉な仕事をしなかったことを意味します。デスクトップJavaアプリケーションを除いて、ほとんどのJavaアプリはロギングを使用する方が良いでしょう。

メソッドの失敗モードが操作なしの場合、理由(および存在)を記録するかどうかに関係なく、例外を食べることはまったく問題ありません。ただし、より一般的には、catch句はある種の例外的なアクションを実行する必要があります。

例外の再スローは、catchを使用して、必要な情報がまだ利用可能なレベルで作業の一部をクリーンアップする場合、または例外を呼び出し元により適した例外タイプに変換する必要がある場合に最適です。


3

キャッチブロックが実際に空の場合にのみ、サイレントに消費されます。

記事に関する限り、例外の処理方法以外に、他のポイントを証明することの方がおそらく興味深いでしょう。彼らはただ要点をまっすぐに理解し、可能な限り短いコードを持ちたいだけです。

明らかにあなたは正しいですが、例外が「無視」される場合は、少なくともログに記録する必要があります。


3

他の人が指摘しているように、これが表示される理由は次の3つの理由のいずれかです。

  1. IDEがtry-catchブロックを生成しました
    • コードをコピーして貼り付けました
    • 開発者はスタックトレースをデバッグに入れましたが、例外を適切に処理するために戻ってきませんでした

最後のポイントは、発生する可能性が最も低いです。誰も実際にこの方法でデバッグするとは思わないので、私はこれを言います。デバッガーを使用してコードをステップ実行すると、デバッグがはるかに簡単になります。

キャッチブロックで何をすべきかについての最良の説明は、JoshuaBlochによるEffectiveJavaの第9章にあります。


2

C#では、すべての例外はランタイム例外ですが、Javaでは、ランタイム例外とチェック済み例外があり、それらをキャッチするか、メソッドで宣言する必要があります。最後に「スロー」があるメソッドを呼び出す場合は、そこに記載されている例外をキャッチするか、メソッドでそれらの例外を宣言する必要があります。

例外処理は記事の主題とは無関係であるため、Java Articlesは通常、スタックトレースを出力するか、コメントを付けます。ただし、プロジェクトでは、例外のタイプに応じて、それについて何かを行う必要があります。


2

プログラマーが自分の仕事を正しく行えば、これは非常に頻繁に見られるはずです。例外を無視することは悪い、悪い習慣です!しかし、一部の人がこれを行う理由と、より適切な解決策がいくつかあります。

  • 「これは起こらない!」確かに、この例外が発生しないことを「知っている」場合もありますが、発生した例外を単に無視するのではなく、「原因」として実行時例外を再スローする方が適切です。私はそれが将来いつか起こるだろうに違いない。;-)

  • コードのプロトタイピングそれがうまくいくかどうかを確認するために入力するだけの場合は、発生する可能性のあるすべての例外を無視することをお勧めします。これは私がいくつかの怠惰なキャッチ(Throwable)を行う唯一のケースです。しかし、コードが何か便利なものになる場合は、適切な例外処理を含めます。

  • 「どうしたらいいのかわからない!」アプリケーションのこのレイヤーでは適切な処理を実行できないため、発生する例外を飲み込むコード、特にライブラリコードをたくさん見ました。これをしないでください!例外を再スローするだけです(メソッドシグネチャにthrows句を追加するか、例外をライブラリ固有の例外にラップします)。


3
catch(Throwable)を見ると、私はうんざりしました。
トカゲのビル

2
絶対に。私はcatch(Throwable)を使用するか、遊んでいる場合はコードでThrowableをスローします。「実際の」コードにはそれを含めてはなりません。限目。
マラックス2009年

同意しました。私は前にそれを見たので私はしわがれます。あなたがcatch(Throwable)を書いたことを他の開発者が見た場合、それは行き過ぎです!:)
トカゲのビル

1
コードがプロセスをシャットダウンしたとしても、最上位レベルで(Throwable)をキャッチしたいのです。1つのスレッドが欠落している状態でぐらつくことを試みることは、最善のアイデアではないかもしれません。
トムホーティン-タックライン2009年

2

常に転送するか、実際のコンテキストで適切に処理する必要があります。多くの記事やチュートリアルでは、コードを単純化してより重要なポイントを伝えますが、単純化する最も簡単な方法の1つはエラー処理です(エラー処理に関する記事を書いている場合を除きます:))。Javaコードは例外処理をチェックするため、単純なサイレント(またはロギングステートメント)catchブロックをオンにするのが、実用的な例を提供する最も簡単な方法です。

サンプルコード以外でこれを見つけた場合は、コードをTDWTFに転送してください。ただし、今ではサンプルが多すぎる可能性があります:)


2

ほとんどのJavaプログラマーは、例外をどう処理するかを知らないのではないかと心配しています。例外は、「主格」のコーディングを遅くする煩わしさだと常に考えています。もちろん、彼らは完全に間違っていますが、例外を正しく処理することが重要であることを彼らに納得させることは困難です。私がそのようなプログラマーに出会うたびに(それは頻繁に起こります)、私は彼に2つの読書エントリーを与えます:

  • 有名なThinkingIn java
  • ここで入手可能なBarryRuzekの短くて興味深い記事:www.oracle.com/technology/pub/articles/dev2arch/2006/11/effective-exceptions.html

ちなみに、RuntimeExceptionに埋め込まれた例外を再スローするために型指定された例外をキャッチするのは愚かであることに強く同意します。

  • あなたがそれを捕まえたら、それを扱ってください。
  • それ以外の場合は、メソッドシグネチャを変更して、処理できる/処理できない可能性のある例外を追加します。これにより、呼び出し元が自分でそれを実行できるようになります。

私はこの問題についてブルース
エッケル

2

チェックされた例外とインターフェースの組み合わせは、コードが決してスローされない例外を処理しなければならないという状況につながります。(同じことが通常の継承にも当てはまりますが、インターフェイスを使用して説明する方が一般的で簡単です)

理由:インターフェースの実装は、インターフェース仕様で定義されているもの以外の例外をスロー(チェック)しない場合があります。そのため、インターフェイスを実装するクラスのどのメソッドが実際に例外をスローする必要があるかを知らないインターフェイスの作成者は、すべてのメソッドが少なくとも1つのタイプの例外をスローする可能性があると指定する場合があります。例:JDBC。すべてとそのおばあちゃんがSQLExceptionをスローするように宣言されています。

しかし実際には、実際の実装の多くの方法は単純に失敗することはないため、いかなる状況でも例外をスローすることはありません。このメソッドを呼び出すコードは、依然として何らかの方法で例外を「処理」する必要があります。最も簡単な方法は、例外を飲み込むことです。決して実行されることのない、一見役に立たないエラー処理でコードを乱雑にしたいと思う人は誰もいません。


1
私見ですが、ランタイムエラーなどの例外をキャッチして再スローするための言語の省略形が必要です。そのような省略形を記すと、コードと動作の両方で、そのような例外は「予期しない」状態を表すものと見なされるべきであることが明らかになります。例外がスローされた場合、何かが深刻に間違っており、呼び出しコードがそれを検出する必要があるため、飲み込むことは悪いことです。
スーパーキャット2014

supercat:私はその考えが好きですが、チェックされた例外の(IMOが疑わしい)利点を打ち消すかもしれません。
Erich Kitzmueller 2014

チェックされた例外が例外クラスではなくキャッチ/スローサイトと例外インスタンスの特性である場合は、チェックされた例外が同じクラスのチェックされていない例外として伝播される可能性がありますが、ラップアンドリスローでさえも大幅に改善されます。現状維持であり、新しい機能として簡単に追加できます。チェックされた例外をそれ自体でスローする可能性のあるメソッドが、同じ例外をスローすると宣言されているが実際にはそうすることが期待されていない他のメソッドを呼び出す場合に特に役立ちます。後者の方法の一つは...スローした場合
supercat

...外部メソッドからスローされた例外を処理することを期待している呼び出し元は、内部メソッドによってスローされた例外をキャッチしないでください。これは、呼び出し元が期待していた条件を表していないためです。ランタイムフレームワークを最初から設計する場合、チェックされた例外とチェックされていない例外には異なるメカニズムを使用します。チェックされた例外は、成功した関数呼び出しにわずかなオーバーヘッドを追加しますが、スローされたときのオーバーヘッドは、チェックされていない例外よりもはるかに少なくなります(とりわけ、チェックされたままの例外にはスタックトレースがありません)。
スーパーキャット2014

1

指摘したように、printStackTrace()の呼び出しは、実際にはサイレント処理ではありません。

この種の例外の「飲み込み」の理由は、チェーンの上位で例外を渡し続ける場合でも、どこかで例外を処理する、アプリケーションをクラッシュさせる必要があるためです。したがって、情報ダンプで発生するレベルで処理することは、情報ダンプでトップレベルで処理することよりも悪くはありません。


1

その怠惰な練習-それ以外の何物でもありません。

これは通常、指の動きを増やすのではなく、例外を本当に気にしないときに行われます。


1

チェックされた例外を再スローする方が良い考えであることに同意しません。キャッチとは取り扱いを意味します。あなたが投げ直す必要があるならば、あなたは捕まえるべきではありません。その場合、メソッドのシグネチャにthrows句を追加します。

チェックされた例外をチェックされていないものにラップすること(たとえば、SpringがチェックされたSQLExceptionをチェックされていない階層のインスタンスにラップする方法)は許容できると言えます。

ロギングは処理と見なすことができます。コンソールに書き込む代わりにlog4jを使用してスタックトレースをログに記録するように例が変更された場合、それは受け入れ可能になりますか?あまり変化はありません、IMO。

本当の問題は、例外的で許容できる回復手順と見なされるものです。例外から回復できない場合は、失敗を報告するのが最善の方法です。


1

チェックされた例外をチェックされていない例外でラップしないでください。

すべきではないと思われる例外に対処していることに気付いた場合、私のアドバイスは、おそらく間違ったレベルの抽象化で作業しているということです。

詳細を説明します。チェックされた例外とチェックされていない例外は、2つのまったく異なる獣です。チェックされた例外は、エラーコードを返す古い方法に似ています...はい、エラーコードよりも処理がやや面倒ですが、利点もあります。チェックされていない例外は、プログラミングエラーと重大なシステム障害です...言い換えれば、例外的な例外です。例外が何であるかを説明しようとすると、多くの人がこれら2つの非常に異なるケースの違いを認識していないため、完全に混乱します。


AssertionErrorでラップすることは私にとって理にかなっています。AssertionErrorは、IMOのどこにでも適用される抽象化です。
日本酒

詳細を説明します。チェックされた例外とチェックされていない例外は、2つのまったく異なる獣です。チェックされた例外は、エラーコードを返す古い方法に似ています...はい、エラーコードよりも処理がやや面倒ですが、利点もあります。チェックされていない例外は、プログラミングエラーと重大なシステム障害です...言い換えれば、例外的な例外です。例外が何であるかを説明しようとすると、多くの人がこれら2つの非常に異なるケースの違いを認識していないため、完全に混乱します。
CurtainDog 2009年

あなたが言うように、おそらく私は完全に混乱している人々の中にいます。ただし、私の本当のポイントは、実行を中断することを選択できる間、実行を続行できるようにする理由です。(AssertionErrorを使用するか、必要に応じてインターフェイスを変更して、追加の例外を含めます

1
この答えの主要な主張にこれ以上反対することはできませんでした。精緻化にはメリットがあります。
ローレンスドル

@CurtainDog:チェックされた例外は「予期される」問題に対するものです。メソッドxが場合によってはFooExceptionをスロー(チェック)し、xを呼び出すメソッドyがそのようなケースの発生を予期しない場合、そのようなケース発生した場合、それらは予期しない問題を表します。を期待しているコールスタックのさらに上に何かがあったとしてもFooException、現在の状況は、aFooExceptionがスローされたときにそのアップストリームの呼び出し元が期待するものと一致しません。
スーパーキャット2014

1

彼らはまだこのトリックを学んでいないので:

class ExceptionUtils {
    public static RuntimeException cloak(Throwable t) {
        return ExceptionUtils.<RuntimeException>castAndRethrow(t);
    }

    @SuppressWarnings("unchecked")
    private static <X extends Throwable> X castAndRethrow(Throwable t) throws X {
        throw (X) t;
    }
}

class Main {
    public static void main(String[] args) { // Note no "throws" declaration
        try {
            // Do stuff that can throw IOException
        } catch (IOException ex) {
            // Pretend to throw RuntimeException, but really rethrowing the IOException
            throw ExceptionUtils.cloak(ex);
        }
    }
}

これは素晴らしいトリックですが、個人的には、「throw new ServiceUnavailableException(ex)」のような原因で、より具体的な例外をスローしたいと思います
Greg

ApacheのExceptionUtilsのrethrowメソッドはまさにこれを行います。それは良いトリックです。github.com/apache/commons-lang/blob/master/src/main/java/org/…–
Lluis Martinez

1

例外の本当のポイントは、エラー処理を簡素化し、エラー検出から分離することです。これは、エラー処理コードがいたるところに散在し、失敗する可能性のあるすべての呼び出しが戻りコードをチェックするエラーコードでエラーを表すのとは対照的です。

例外がエラーを表す場合(ほとんどの場合)、通常、例外を処理する最も合理的な方法は、ベイルアウトして処理を上位層に任せることです。意味のあるセマンティクスが追加されている場合は、別の例外の再スローを検討する必要があります。つまり、このエラーは異常なシステム障害/一時的な(ネットワーク)問題です/これはクライアントまたはサーバー側のエラーなどです。

すべてのエラー処理戦略の中で、最も無知なのは、エラーメッセージを非表示にするか、単に印刷して、何も起こらなかったために先に進むことです。


Sunの人々は、コードをより明示的にしたいと考えており、プログラマーはどの例外がどのメソッドでスローされるかを記述する必要がありました。それは正しい動きのようでした-プロトタイプが与えられた場合、メソッド呼び出しからの見返りとして何を期待するかは誰でも知っています(このタイプの値を返すか、指定されたクラスの1つ(またはそのサブクラス)のインスタンスをスローする可能性があります)。

しかし、多くの無知なJavaプログラマーが判明したため、例外処理を言語のバグ/「機能」であるかのように扱い、回避策が必要であり、最悪またはほぼ最悪の方法でコードを記述します。

  • エラーは、それをどう処理するかを決定するのに適していないコンテキストですぐに処理されます。
  • サイレントに表示または無視され、それ以上のコードが適切に実行されない場合でも計算が続行されます。
  • メソッドの呼び出し元は、正常に終了したかどうかを区別できません。

より「正しい方法」を書く方法は?

  • メソッドヘッダーでスローされる可能性のある例外のすべての基本クラスを示します。AFAICREclipseはそれを自動的に行うことができます。
  • メソッドプロトタイプのスローリストを意味のあるものにします。長いリストは無意味であり、「例外をスローする」は怠惰です(ただし、例外についてあまり気にしない場合に役立ちます)。
  • 「間違った方法」を書くときは、「try {...} catch(Exception e){e.printStackTrace();}」よりも単純な「throwException」の方がはるかに優れており、バイト数も少なくて済みます。
  • 必要に応じて、連鎖例外を再スローします。

0

例外を現在のメソッドの範囲外で処理する場合は、実際にキャッチする必要はありません。代わりに、メソッドのシグネチャに「throws」ステートメントを追加します。

あなたが見たtry / catchステートメントは、プログラマーが例外をその場で処理することを明示的に決定したコードにのみあり、したがってそれ以上スローしません。


1
真実ではありません-'throws '宣言のないインターフェイスメソッドを実装している場合、またはスーパークラスメソッドをオーバーライドしている場合は、単に追加することはできません。そのような場合は、RuntimeExceptionで例外をラップするか、それを飲み込む必要があります。
Martin McNulty

0

開発者も、特定のコンテキストで「正しいことをする」ことの重要性を考慮しようとしていると思います。多くの場合、コードを破棄したり、例外を上向きに伝播しても例外が致命的であるために何も購入されない場合は、「間違ったことをする」ことで時間と労力を節約したほうがよいでしょう。


0

通常、例外から回復できない場合は例外を飲み込みますが、それは重要ではありません。1つの良い例は、データベース接続を閉じるときにスローされる可能性のあるIOExcetionです。これが発生した場合、本当にクラッシュしますか?そのため、ジャカルタのDBUtilsにはcloseSilentlyメソッドがあります。

ここで、回復できないが重大である(通常はプログラミングエラーが原因である)チェック済み例外については、それらを飲み込まないでください。例外は問題の原因にできるだけ近い場所でログに記録する必要があると思うので、printStackTrace()呼び出しを削除することはお勧めしません。ビジネスメソッドでこれらの例外を宣言する必要がないという唯一の目的のために、それらをRuntimeExceptionに変換することをお勧めします。createClientAccount()がProgrammingErrorException(SQLExceptionを読み取る)をスローするなどの高レベルのビジネスメソッドを使用することは実際には意味がありません。SQLにタイプミスがある場合や不正なインデックスにアクセスする場合は何もできません。


0

経験上、例外を飲み込むことは、ほとんどの場合、印刷されていない場合に有害です。クラッシュした場合に注意を引くのに役立ちます。意図的にそれを行うこともありますが、例外を出力して続行するだけで、問題を見つけて修正できますが、通常、同じコードベースで作業している他のユーザーに悪影響を与えることはありません。 。

私は実際にFail-Fast / Fail-HARDに夢中ですが、少なくともそれを印刷します。例外を実際に「食べる」場合(これは本当に何もしないことです:{})誰かがそれを見つけるのに数日かかります。

問題は、Javaが、開発者がスローされないことを知っている、またはスローされても気にしない多くのものをキャッチするように強制することです。最も一般的なのはThread.sleep()です。ここにスレッドの問題を引き起こす可能性のある穴があることはわかっていますが、一般的には、それを中断していないことを知っています。限目。


0

catchExceptionを使用する理由はたくさんあります。多くの場合、RuntimeExceptionsもキャッチするため、これは悪い考えです。これが発生した後、基になるオブジェクトがどのような状態になるかわかりませんか?これは、予期しない状況では常に困難なことです。コードの残りの部分が後で失敗しないことを信頼できますか。

あなたの例はスタックトレースを出力するので、少なくとも根本的な原因が何であったかがわかります。大規模なソフトウェアプロジェクトでは、これらをログに記録することをお勧めします。そして、ログコンポーネントが例外をスローしないことを期待しましょう。無限ループに陥る可能性もあります(おそらくJVMが強制終了されます)。


0

チェックされた例外があり、それをメソッドで処理したくない場合は、メソッドに例外をスローさせる必要があります。何か便利なことをする場合にのみ、例外をキャッチして処理します。ユーザーがログを読んで例外を探したり、例外がスローされた場合の対処方法を知ったりする時間がほとんどないため、ログを記録するだけでは、私の本ではあまり役に立ちません。

例外をラップすることはオプションですが、次の場合を除いて、これを行うことはお勧めしません。既存のインターフェイスに一致するように別の例外をスローするか、そのような例外をスローする方法は実際にはありません。

ところで:チェックされた例外を再スローしたい場合は、これを行うことができます

try {
   // do something
} catch (Throwable e) {
   // do something with the exception
   Thread.currentThread().stop(e); // doesn't actually stop the current thread, but throws the exception/error/throwable
}

注:これを行う場合、コンパイラーはこの状況ではこれを行うことができないため、メソッドのthrows宣言が正しいことを確認する必要があります。


ただFTR:Thread#stop()は非推奨になり、その間に無効になりました(スローしますUnsupportedOperationException)。
maaartinus 2017

-2

それがベストプラクティスだからです。誰もが知っていると思いました。
しかし、冷酷な真実は、例外を除いて作業する方法を本当に理解している人は誰もいないということです。Cエラー処理スタイルは非常に理にかなっています。


1
多くの開発者が例外を無視しないからといって、「エラーリターン」が改善されるわけではありません。エラーを処理するCの方法は、今もなお、ひどくエラーが発生しやすい(しゃれを意図した)メカニズムです。例外を飲み込むこと(この例では、サイレントではありません)は、戻り値をチェックせずにCで関数を呼び出すことに似ています。最終結果は同じです-プログラムは「失敗」します。この例では、悪いC.として扱うJavaエラーを作成する場合だけである
ローレンスDolのが
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.