彼がヌルを期待していない場合、ヌルをチェックする必要がありますか?


113

先週、アプリケーションのサービスレイヤーでnullを処理することについて、激しい議論がありました。問題は.NETコンテキストにありますが、Javaや他の多くのテクノロジーでも同じです。

問題は、nullを常にチェックし、何があってもコードを動作させるか、nullが予期せず受信されたときに例外を発生させるか、ということでした。

一方で、nullを期待していない(つまり、それを処理するユーザーインターフェイスがない)ところをチェックすることは、catchを空にしてtryブロックを記述することと同じです。エラーを隠しているだけです。エラーは、コード内で何かが変更され、nullが予期される値になったこと、または他のエラーがあり、間違ったIDがメソッドに渡されたことが考えられます。

一方、nullをチェックすることは一般的に良い習慣です。さらに、チェックがある場合、アプリケーションが機能し続ける可能性がありますが、機能のごく一部が効果を発揮しません。次に、「ページXを開くことができない」などのより深刻なバグの代わりに、「コメントを削除できない」などの小さなバグを報告する場合があります。

あなたはどのような慣習に従い、どちらのアプローチに対して賛成または反対ですか?

更新:

特定のケースに関する詳細を追加します。データベースからいくつかのオブジェクトを取得し、それらに対して何らかの処理を行いました(たとえば、コレクションを構築します)。コードを記述した開発者は、オブジェクトがnullになる可能性があることを予期していなかったため、チェックを含めず、ページが読み込まれたときにエラーが発生し、ページ全体が読み込まれませんでした。

明らかに、この場合はチェックが必要でした。次に、処理されるすべてのオブジェクトを、欠落していることが予想されない場合でもチェックする必要があるかどうか、および最終的な処理をサイレントに中止するかどうかについて議論しました。

仮想的な利点は、ページが引き続き機能することです。Stack Exchangeのさまざまなグループ(ユーザー、コメント、質問)の検索結果を考えてください。メソッドはnullをチェックし、ユーザーの処理を中止できます(バグがnullのため)が、「comments」および「questions」セクションを返します。「ユーザー」セクションが欠落することを除いて、ページは引き続き機能します(これはバグです)。早期に失敗してページ全体を壊すか、作業を続けて「ユーザー」セクションが欠落していることに誰かが気付くのを待つべきでしょうか?


62
フォックス・モルダーの原則:誰も信用しない。
ヤニス

14
@YannisRizos:その原則は良いものです-JavaとC#の作成者が言語ランタイム環境にこれを自動的に行わせるのはとても良いことです。そのため、通常、これらの言語のコードのどこでも、nullを明示的にチェックする必要はありません。
ドックブラウン


私はtdammersの回答に同意します。nullをチェックするのは、それを処理する合理的な方法がないため、間違っていると思います。ただし、シナリオでは、ユーザーの検証(またはコメントなど)の失敗や「エラーが発生しました」ボックスの表示などのセクションの失敗を処理できます。個人的にすべての例外をアプリに記録し、404などの特定の例外を除外し、予期せず接続を閉じます

2
assert(foo != null, "foo is web control within the repeater, there's no reason to expect it to be null, etc, etc...");
zzzzBov

回答:


105

問題はnull、ランタイムをチェックするか例外をスローさせるかではありません。それはあなたがそのような予期せぬ状況にどのように対応すべきかということです。

その場合のオプションは次のとおりです。

  • 一般的な例外(NullReferenceException)をスローして、バブルアップさせます。null自分でチェックを行わない場合、これは自動的に行われます。
  • より高いレベルで問題を説明するカスタム例外をスローします。これは、nullチェックをスローするかNullReferenceException、より具体的な例外をキャッチしてスローすることで実現できます。
  • 適切なデフォルト値に置き換えて復旧します。

どれが最良の解決策であるかという一般的なルールはありません。個人的に、私は言うだろう:

  • 一般的な例外は、エラー状態がコードの重大なバグの兆候である場合に最適です。つまり、nullの値が最初にそこに到達することは許可されません。そのような例外は、設定したエラーロギングに完全にバブルアップし、誰かに通知されてバグを修正します。
  • 技術的に正しくないHTMLを受け入れ、賢明にレンダリングするために最善の努力をするWebブラウザーなど、半有用な出力を提供することが正確さよりも重要である場合、デフォルト値ソリューションは適切です。
  • それ以外の場合は、特定の例外を使用して適切な場所で処理します。

1
エンドユーザー向けの@Stilgarには違いはありません。開発者に対しは、「データベース・サーバーに到達できない」などの特定の例外は「nullポインタexcepteion」という、より直感的である
K3B

32
ハードかつ早期の失敗は、物事がより微妙に間違って行くリスク、誤認証、破損したデータがストレージに保持される、情報漏洩、その他の面白いことなどのリスクが少ないことを意味します。
ラースヴィクルンド

1
@Stilgar:ここには2つの懸念事項があります。無人動作と保守性です。無人の動作では、特定の例外と一般的な例外の間にほとんど違いはありませんが、保守性のために、「ああ、だから物事が爆発する」と数時間のデバッグアスロンとの違いを作ることができます。
-tdammers

3
tdammersはまさに正しい。「オブジェクトのインスタンスに設定されていないオブジェクト参照」は、最も頻繁に見られる最も厄介な例外の1つです。パラメータ名を持つArgumentNullExceptionであろうと、カスタム例外「ユーザーTK421のPostレコードが存在しない」であろうと、特定の例外が表示されます。
ショーンチェイス

1
@ k3bエンドユーザーにとっても、「データベースサーバーにアクセスできません」は非常に役立ちます。少なくとも、一般的な問題について少し手掛かりを持っているエンドユーザーにとっては、バグの多いソフトウェアに腹を立てるのではなく、ケーブルが緩んでいる、ルーターを再起動する必要があるなどの発見に役立つかもしれません。
ジュリアヘイワード

58

予期しないヌル値を処理しようとすると、コードが非常に複雑になります。nullが予期されない場合は、をスローしてnullを明確にしArgumentNullExceptionます。値がnullであるかどうかを確認し、意味のないコードを記述しようとすると、本当にイライラします。同じことはSingleOrDefault、誰かが本当に期待Singleしている場合や、人々が自分のロジックを明確に述べることを恐れている(実際は何を知らない)他の多くの場合に使用します(またはコレクションを取得することはさらに悪い)。


の代わりにArgumentNullException、コードコントラクトを使用する必要があります(コードコントラクトをサポートしない2010年以前のソースコードの場合を除く)。
アルセニムルゼンコ

仰るとおりです。nullが予期されていない場合、奇妙な方法で処理されるべきではなく、報告されるだけです。
ジョルジオ

9
質問を読み、ArgumentNullExceptionnull値を「処理」するものとしてカウントをスローすると、後でnull参照例外が発生しなくなります。
KutuluMike

@MichaelEdenfield:それは、与えられた質問に従って実際の処理としてカウントされるとは思わない(私たちの目標は、コードが何であっても機能するようにすることではない)。正直に言うと、nullが渡された場合にスローする適切なブロックの作成を忘れることがよくあります。しかし、私はNullArgumentExceptionをスローすることをベストプラクティスと考えており、私の意見では最悪のプラクティスは、nullを処理できないが例外を返す代わりにメソッド結果として別のnull(または空の文字列、空のコレクション、または-1 、または戻り値の型がvoidなどの場合はメソッドの実行をスキップします)。
エンピ

2
@GiorgioはArgumentNullException、問題の内容と修正方法を非常に明確にします。C#は「未定義」を使用する傾向はありません。定義されていない方法で何かを呼び出す場合、それを呼び出す方法は意味がありません。例外は、それを示す適切な方法です。ここで、int(たとえば)を解析できない場合にnullを返す解析メソッドを作成することがあります。しかし、それは、解析不能な結果が使用エラーではなく正当な可能性である場合です。この記事も参照してください
キラレッサ

35

null私の経験をチェックする習慣は、元のCまたはC ++開発者から来ています。これらの言語では、チェックしないときに重大なエラーを隠す可能性が高くなりますNULL。ご存じのように、JavaまたはC#では状況が異なり、チェックせずにnull refを使用nullすると例外が発生するため、呼び出し側で無視しない限り、エラーは密かに隠されません。そのため、ほとんどの場合、明示的にチェックnullすることはあまり意味がなく、必要以上にコードが複雑になります。そのため、これらの言語ではnullチェックを良い習慣と見なしていません(少なくとも、一般的にはそうではありません)。

もちろん、そのルールには例外があります。ここに私が考えることができるものがあります:

  • より良い、人間が読めるエラーメッセージが必要で、プログラムのどの部分で間違ったnull参照が発生したかをユーザーに伝えます。そのため、nullのテストでは、エラーテキストが異なる、異なる例外のみがスローされます。明らかに、そのようにエラーがマスクされることはありません。

  • あなたのプログラムを「もっと早く失敗させたい」。たとえば、コンストラクターパラメーターのnull値を確認する場合、そうでない場合は、オブジェクト参照はメンバー変数にのみ格納され、後で使用されます。

  • null refの状況に安全に対処できます。その後の障害のリスクがなく、重大なエラーをマスクする必要もありません。

  • 現在のコンテキストで完全に異なる種類のエラーシグナリング(たとえば、エラーコードを返す)が必要な場合


3
「より良い、人間が読めるエラーメッセージが必要です」-私の意見では、それがそれを行うための最良の理由です。「オブジェクト参照がオブジェクトのインスタンスに設定されていない」または「NULL参照例外」は、「製品がインスタンス化されていない」ほど有用ではありません。
-pdr

@pdr:チェックするもう1つの理由は、常に検出されることを確認することです。
ジョルジオ

13
「元C開発者」、おそらく。「以前のC ++開発者」は、それら自体がC開発者を回復している場合のみ。現代のC ++開発者として、私は裸のポインターまたは無謀な動的割り当てを使用するコードについて非常に疑っています。実際、私は議論を好転させ、C ++はOPが記述する問題を被らないと言いたいと思うでしょう。なぜならその変数はJavaとC#が持っている特別なnull-nessプロパティを持たないからです。
ケレックSB

7
最初の段落はストーリーの半分に過ぎません。はい、C#でnull参照を使用すると例外が発生しますが、C ++では未定義の動作が発生します。しかし、適切に作成されたC#では、適切に作成されたC ++よりもはるかに多くのNULL可能参照に悩まされます。
ジェームズマクネリス

カプセル化が優れているほど、この回答はより適切に適用されます。
レーダーボブ

15

アサートを使用して、コードの事前/事後条件および不変条件をテストおよび指示します。

これにより、コードが何を期待し、何を処理することが期待できるかを非常に簡単に理解できます。

アサートIMOは、次の理由から適切なチェックです。

  • 効率的(通常はリリースでは使用されません)、
  • 簡潔(通常は1行)および
  • クリア(前提条件違反、これはプログラミングエラーです)。

自己文書化コードは重要だと思うので、チェックするのは良いことです。防御的でフェイルファーストのプログラミングは、メンテナンス方法を簡単にします。これは通常、ほとんどの時間が費やされる場所です。

更新

あなたのエラボレーションについて。通常、エンドユーザーにバグの下で適切に動作する、つまり可能な限り表示するアプリケーションを提供するのは良いことです。堅牢性は優れています。なぜなら、天国は重大な瞬間に何が壊れるかしかわからないからです。

ただし、開発者とテスターはバグをできるだけ早く認識している必要があるため、問題があることをユーザーに警告を表示できるフック付きのロギングフレームワークが必要になるでしょう。アラートはおそらくすべてのユーザーに表示されるはずですが、ランタイム環境に応じて異なる方法で調整できます。


リリースには存在しないことは、私にとって大きなマイナスでアサート、リリースには、追加した情報が必要な正確な時間である
JK。

1
必要な場合は、リリースでもアクティブなassert ^ h ^ h ^ hconditional throw関数を使用してください。私はかなり頻繁に自分自身をロールバックしました。
マッケ

7

早く失敗し、頻繁に失敗します。nullは、使用しようとするとすぐに失敗する可能性があるため、取得できる最良の予期しない値の1つです。他の予期しない値を検出するのはそれほど簡単ではありません。null使用しようとするたびに自動的に失敗するので、明示的なチェックを必要としません。


28
私はあなたが意味を願って:初期の失敗、高速で失敗し、ないことが多い...
EMPI

12
問題は、明示的なチェックを行わないと、例外が発生する前にヌル値が伝播することがあり、それがどこから発生したかを見つけるのが非常に困難になる場合があることです。
マイケルボルグワード

@MichaelBorgwardtそれは、スタックトレースの目的ではありませんか?
-R0MANARMY

6
@ R0MANARMY:null値がいくつかのフィールドに保存され、NullPointerExceptionがかなり後でスローされる場合、スタックトレースは役に立ちません。
マイケルボルグワード

@ R0MANARMYスタックトレースの行番号を信頼できた場合でも(多くの場合、信頼できません)、一部の行にはnullの可能性のある複数の変数が含まれています。
オハドシュナイダー

6
  • ヌルをチェックすることはあなたの第二の性質であるべきです

  • あなたのAPIは他の人々によって使用され、彼らの期待はあなたのものとは異なる可能性が高い

  • 徹底した単体テストは通常​​、null参照チェックの必要性を強調しています

  • nullのチェックは、条件ステートメントを意味しません。nullチェックによりコードが読みにくくなることが心配な場合は、.NETコードコントラクトを検討することをお勧めします。

  • ReSharper(または同様の)をインストールして、欠落したnull参照チェックのコードを検索することを検討してください


前提条件にコードコントラクトを使用することは、単に条件付きステートメントを美化したものです。
CVn

はい、同意しますが、コードコントラクトを使用するとコードがきれいに見える、つまり読みやすさが向上すると思います。
CodeART

4

セマンティクスの観点から質問を検討します。つまり、NULLポインターまたはNULL参照引数が何を表すかを自問します。

関数またはメソッドfoo()に型Tの引数xがある場合、xは必須またはオプションのいずれかです

C ++では、必須の引数を次のように渡すことができます。

  • 値、たとえばvoid foo(T x)
  • 参照、例えばvoid foo(T&x)。

どちらの場合でも、NULLポインターをチェックする問題はありません。だから、多くの場合、あなたはnullポインタチェックを必要としないで、すべての必須の引数について。

オプションの引数を渡す場合、ポインターを使用し、値が指定されていないことを示すためにNULL値を使用できます。

void foo(T* x)

別の方法は、次のようなスマートポインターを使用することです。

void foo(shared_ptr<T> x)

この場合、おそらくコード内のポインターを確認する必要があります。これは、xに値が含まれているか値がまったく含まれていないかによってメソッドfoo()に違いが生じるためです。

3番目の最後のケースは、必須 引数にポインターを使用することです。この場合、x == NULLでfoo(x)を呼び出すことはエラーであり、これを処理する方法を決定する必要があります(範囲外のインデックスまたは無効な入力の場合と同じ)。

  1. チェックなし:バグがある場合、クラッシュさせて、このバグが十分に早く現れることを願っています(テスト中)。そうでない場合(十分に早く失敗しない場合)、ユーザーエクスペリエンスはアプリケーションのクラッシュを確認できるため、運用システムに表示されないことを期待します。
  2. メソッドの先頭にあるすべての引数を確認し、無効なNULL引数を報告します。たとえば、foo()から例外をスローし、他のメソッドにそれを処理させます。おそらく最善の方法は、アプリケーションに内部エラーが発生し、終了することを通知するダイアログウィンドウをユーザーに表示することです。

失敗のより良い方法(ユーザーにより多くの情報を与える)とは別に、2番目のアプローチの利点は、バグが発見される可能性が高いことです:メソッドが間違った引数で呼び出されるたびにプログラムが失敗しますアプローチ1では、ポインターを逆参照するステートメントが実行された場合にのみバグが表示されます(ifステートメントの右ブランチが入力された場合など)。そのため、アプローチ2は「早期失敗」のより強力な形式を提供します。

Javaでは、すべてのオブジェクトが常にnullになる可能性のある参照を使用して渡されるため、選択肢が少なくなります。繰り返しますが、nullがオプションの引数のNONE値を表す場合、nullのチェックは(おそらく)実装ロジックの一部になります。

nullが無効な入力である場合、エラーが発生し、C ++ポインターの場合と同様の考慮事項を適用します。Javaではnullポインター例外をキャッチできるため、メソッドfoo()がすべての実行パスのすべての入力引数を参照する場合、上記のアプローチ1はアプローチ2と同等です(おそらく小さなメソッドで非常に頻繁に発生します)。

要約する

  • C ++とJavaの両方で、オプションの引数がnull かどうかをチェックすることは、プログラムのロジックの一部です。
  • C ++では、プログラムが堅牢な方法で処理できるように、常に必須の引数をチェックして適切な例外がスローされることを確認します。
  • Java(またはC#)では、「フェイルアーリー」というより強力な形式にするためにスローしない実行パスがある場合、必須の引数をチェックします

編集

詳細については、Stilgarに感謝します。

あなたの場合、メソッドの結果としてnullを持っているようです。繰り返しますが、決定を下す前に、まずメソッドのセマンティクスを明確にする(そして修正する)必要があると思います。

したがって、メソッドm2()を呼び出すメソッドm1()があり、m2()はオブジェクトへの参照(Javaの場合)またはポインター(C ++の場合)を返します。

m2()のセマンティクスは何ですか?m2()は常にnull以外の結果を返す必要がありますか?この場合、null結果は内部エラー(m2()内)です。m1()で戻り値をチェックすると、より堅牢なエラー処理が可能になります。そうしないと、遅かれ早かれ、おそらく例外が発生するでしょう。そうでないかもしれない。展開後ではなく、テスト中に例外がスローされることを願っています。質問:m2()がnullを返すべきでない場合、なぜnullを返すのですか?代わりに例外をスローする必要がありますか?m2()はおそらくバグです。

別の方法として、nullを返すことはメソッドm2()のセマンティクスの一部です。つまり、オプションの結果があり、メソッドのJavadocドキュメントに文書化する必要があります。この場合、null値を使用してもかまいません。メソッドm1()は、他の値と同じようにチェックする必要があります。ここではエラーはありませんが、おそらく結果がnullかどうかをチェックすることは、プログラムロジックの一部にすぎません。


場合によっては、引数がヌルではなかった。存在すると予想されていたものを実際にデータベースに呼び出しましたが、実際には存在しませんでした。問題は、すべてのオブジェクトが存在することを確認する必要があるか、それとも欠落していると予想される場合にのみ確認する必要があるかです。
スティルガー

したがって、メソッドによって返される結果はオブジェクトへの参照であり、nullは結果を表すために使用される値でした:NOT FOUND。正しく理解できますか?
ジョルジオ

質問を追加の詳細で更新しました。
スティルガー

3

私の一般的なアプローチは、処理方法がわからないエラー状態をテストしないことです。次に、特定の各インスタンスで回答する必要がある質問は次のようになります。予期しない値が存在する場合に合理的なことを実行できますnullか?

別の値(たとえば、空のコレクション、またはデフォルト値またはインスタンス)に置き換えて安全に続行できる場合は、必ずそうしてください。ある画像を別の画像に置き換えるというWorld of Warcraft@Shahbazの例は、そのカテゴリに分類されます。画像自体はおそらく単なる装飾であり、機能的な影響はありません。(デバッグビルドでは、置換が行われたという事実に注意を喚起するために叫び声の色を使用しますが、それはアプリケーションの性質に大きく依存します。)しかし、エラーに関する詳細を記録します。そうしないと、おそらく知りたいエラーを隠すことになります。ユーザーからそれを隠すことは一つのことです(再び、処理が安全に続行できると仮定します)。開発者からそれを隠すことは全く別です。

null値があると安全に続行できない場合は、理にかなったエラーで失敗します。一般に、操作が成功しないことが明らかな場合は、できるだけ早く失敗することを好みます。これは前提条件のチェックを意味します。すぐに失敗したくないが、できる限り失敗を延期する場合があります。この考慮事項は、たとえば暗号化関連のアプリケーションで発生します。このアプリケーションでは、サイドチャネル攻撃により、知らない情報が漏えいする可能性があります。最後に、エラーをいくつかの一般的なエラーハンドラーにバブルし、関連する詳細をログに記録し、ユーザーに素敵な(ただし、素敵な)エラーメッセージを表示します。

また、テスト/ QA /デバッグビルドとプロダクション/リリースビルドとでは、適切な応答が非常に異なる場合があることに注意してください。デバッグビルドでは、問題があることを完全に明らかにし、事後分析でそれを修正するために何をする必要があるかを決定できるように、非常に詳細なエラーメッセージで早期に失敗します。プロダクションビルドは、安全に回復可能なエラーに直面した場合、おそらく回復を支持するはずです。


もちろん、チェーンの上位に一般的なエラーハンドラがあります。ログの問題は、ログを非常に長い間チェックする人がいない可能性があることです。
Stilgar

@Stilgar、ログをチェックする人がいなければ、nullチェックの有無に問題はありません。
CVn

2
問題がある。エラーを単に隠してログに書き込むヌルチェックがある場合、エンドユーザーはシステムが長時間正しく動作しないことに気付かない場合があります。
スティルガー

@Stilgar、それは完全にエラーの性質に依存します。投稿で述べたように、安全に続行できる場合にのみ、予期しないnullを置き換え/無視する必要があります。たとえば、リリースビルドで別のイメージの代わりに1つのイメージを使用する(デバッグビルドでは、できるだけ早く失敗して問題が明らかになるため)ため、無効な計算結果を返すこととは非常に異なります。(それを含むように回答を編集しました。)
CVn

1
どうにかしてエラーをログに記録して報告できる場合を除き(運用に精通しているユーザーに頼りすぎずに)、本番環境でも早く失敗します。デプロイされたバグをユーザーから隠すことは一つのことです-自分からそれらを隠すことは危険です。また、ユーザーが微妙なバグに耐えることができるようにすると、アプリケーションに対する自信を損なう可能性があります。時々、弾丸を噛んで、バグがあり、それをすぐに修正したことを彼らに知らせる方が良いでしょう。
マーリンモーガングラハム

2

確かに期待されてNULLいませんが、常にバグがあります!

期待していないかどうか確認する必要があると思いますNULL。例を挙げましょう(Javaではありませんが)。

  • World of Warcraftでは、バグにより、開発者の1人の画像が多くのオブジェクトのキューブに表示されました。グラフィックスエンジンがなかった場合を想像し期待する NULLポインタを、それがユーザにとってそれほど致命的ではありません(でも面白い)経験になった一方で、クラッシュがあっただろう。少なくとも、接続やセーブポイントが予期せず失われることはありません。

    これは、NULLのチェックがクラッシュを防ぎ、ケースが静かに処理された例です。

  • 銀行窓口プログラムを想像してください。インターフェースはいくつかのチェックを行い、入力データを基になる部品に送信して送金を実行します。コアパーツが受信しないことを期待している場合、NULLインターフェイスのバグがトランザクションに問題を引き起こす可能性があります。

    「問題」とは、クラッシュを意味します(クラッシュクラッシュ(プログラムはC ++で記述されているなど)、nullポインター例外ではありません)。この場合、NULLが検出された場合、トランザクションはロールバックする必要があります(もちろん、変数をNULLに対してチェックしなかった場合は不可能です!)

きっとあなたはそのアイデアを得たと思います。

関数の引数の妥当性をチェックしても、コードが乱雑になることはありません。これは、関数の上部でいくつかのチェックを行い(中央に拡散しない)、堅牢性を大幅に向上させるためです。

「プログラムが失敗したことをユーザーに通知し、正常にシャットダウンするか、エラーログを作成する可能性がある一貫した状態にロールバックする」と「アクセス違反」のどちらかを選択する必要がある場合、最初のものを選択しませんか?つまり、すべての関数は、バグが常に存在するという理由だけで、すべてが正しいことを期待するのではなく、バグのあるコードによって呼び出されるように準備する必要があります。


2番目の例はあなたの主張を裏付けています。銀行取引では、何か問題が発生した場合、取引は中止されます。お金を失ったり複製したりできるのは、まさにエラーをカバーするときです。nullの確認は、「顧客がnullのお金を送信します...まあ、私はちょうど10ドル(開発者の画像に相当)を送信します」
-Stilgar

@Stilgar、その反対!NULLの確認はメッセージで中止されます。NULLをチェックしないとクラッシュします。トランザクションの開始時のクラッシュは悪くないかもしれませんが、途中で壊滅的なことができます。(銀行振込がゲームのようにエラーを処理する必要があるとは言いませんでした!それ処理する必要があるという事実だけ)
-Shahbaz

2
「トランザクション」のポイントは、半分完了できないことです:)エラーがある場合、ロールバックされます。
-Stilgar

これは、トランザクションのセマンティクスが実際に必要とされるあらゆるものに対するひどいアドバイスです。すべてのトランザクションをアトミックかつべき等にする必要があります。そうしないと、エラーがあるとリソースの損失または重複が保証されます(金額)。非アトミックまたは非べき等の操作を処理する必要がある場合は、アトミックおよびべき等の動作を保証するレイヤーで非常に慎重にラップする必要があります(これらのレイヤーを自分で記述する必要がある場合でも)。常に考えてください:このトランザクションが進行中に流星がWebサーバーにヒットするとどうなりますか?
マーリンモーガングラハム

1
@ MerlynMorgan-Graham、そうしました。混乱が解消されることを願っています。
シャーバズ

2

他の答えが指摘したように、もしあなたが期待していないならNULL、投げて明確にしてくださいArgumentNullException。私の見解では、プロジェクトをデバッグするときに、プログラムのロジックの障害をより早く発見するのに役立ちます。

したがって、ソフトウェアをリリースします。これらのNullRefrencesチェックを復元しても、ソフトウェアのロジックに何も見逃すことはありません。重大なバグが発生しないことを確実に倍増します。

別のポイントは、NULLチェックが関数のパラメーターにある場合、関数がそれを行うのに適切な場所であるかどうかを決定できることです。そうでない場合は、関数へのすべての参照を見つけてから、パラメーターを関数に渡す前に、null参照につながる可能性のあるシナリオを確認してください。


1

nullシステム内のすべてが、発見されるのを待っている時限爆弾です。nullコードが制御していないコードと相互作用する境界で確認しnull、独自のコード内で禁止します。これにより、外部コードを単純に信頼することなく、問題を取り除くことができます。代わりに、例外またはある種のMaybe/ Nothingタイプを使用してください。


0

nullポインター例外は最終的にスローされますが、多くの場合、nullポインターを取得した地点から遠く離れてスローされます。できるだけ早くNULLポインターをgitするという事実を記録することで、バグを修正するのにかかる時間を短縮してください。

今何をすべきかわからなくても、イベントをログに記録すると後で時間を節約できます。そして、チケットを取得した人は、保存された時間を使用して適切な応答を見つけることができるでしょう。


-1

以来Fail early, fail fast、ウェブアプリケーションを使用して、ルールを適用する必要があるバグの下でうまく機能しなければならないためとして@DeadMG(@empi)で述べられてはpssibleではありません

ロギングなしでキャッチする例外はありません

そのため、開発者はログを調べることで潜在的な問題を認識しています。

log4netやlog4jなどのロギングフレームワークを使用している場合は、エラーと致命的なエラーをメールで送信する特別なロギング出力(アペンダーとも呼ばれる)追加セットアップできますだからあなたは情報にとどまる

[更新]

ページのエンドユーザーがエラーを認識していない場合は、エラーと致命的なエラーをメールで送信するアペンダーを設定できます。

ページのエンドユーザーが不可解なエラーメッセージを表示してもよい場合は、ページ処理のエラーログをページの最後に配置するアペンダーをセットアップできます。

例外を飲み込んだ場合、どのようにロギングを使用しても、プログラムは意味のあるデータを続行し、飲み込むことはもう静かではありません。


1
問題は、ページに何が起こるかです。
Stilgar

データが理にかなっており、システムが一貫した状態にあることをどのようにして知ることができますか。結局、エラーは予想外だったので、その影響がわからないのです。
-Stilgar

「早期に失敗するので、@ DeadMG(@empi)で示されているように高速で失敗することは、Webアプリケーションがルールを実施するバグの下でうまく機能する必要があるため、pssibleではありません」:常にすべての例外をキャッチできます(catch(Throwable t))およびエラーページにリダイレクトします。これは不可能でしょうか?
ジョルジオ

-1

この質問にはすでに良い答えがありますが、それらに追加することもできます。コードではアサーションを好みます。コードが有効なオブジェクトでのみ機能するが、nullで機能する場合は、null値でアサートする必要があります。

この種の状況でのアサーションにより、ユニットおよび/または統合テストが正確なメッセージで失敗するため、生産前に問題をかなり迅速に特定できます。そのようなエラーがテストをすり抜けて本番環境(アサーションを非アクティブ化する必要がある場合)に進むと、NpExと重大なバグが発生しますが、よりファジーでマイナーなバグが他のどこかにポップアップするよりも優れていますコード、および修正するにはより高価になります。

さらに、誰かがコードアサーションで作業する必要がある場合は、コードの設計/作成中に行った仮定について伝えます(この場合:おいおい、このオブジェクトを提示する必要があります!)。


投票するために何か書いていただけますか?議論をお願いします。ありがとう
GET

私は反対票を投じなかったし、あなたの一般的な考えに同意する。しかし、言語にはいくつかの作業が必要です。アサーションはAPIのコントラクトを定義し、それらのコントラクトに違反すると、早期/失敗に失敗します。アプリケーションのスキンでこれを行うと、コードのユーザーはコードで何か間違ったことをしたことを知ることができます。彼らがあなたのコードの奥にスタックトレースを見つけた場合、彼らはあなたのコードがバグだと思うでしょう。
マーリンモーガングラハム

-1

通常、nullをチェックしますが、nullが発生した正確な場所についてもう少し詳細を示す例外をスローすることで、予期しないnullを「処理」します。

編集:何かが間違っていると思わないときにnullを取得した場合-プログラムは死ぬはずです。


-1

例外の言語実装に依存します。例外を使用すると、システムが予期しない状態または状態になった場合に、データの損傷を防ぐためのアクションを実行したり、リソースを完全に解放したりできます。これは、予期できる状態であるエラー処理とは異なります。私の哲学は、例外処理をできる限り少なくすることです。ノイズです。あなたのメソッドは例外を処理することで合理的なことをすることができますか?回復できますか?さらなる損傷を修復または防止できますか?例外をキャッチしてからメソッドから戻るか、他の無害な方法で失敗するだけの場合、例外をキャッチすることは本当に意味がありません。メソッドにノイズと複雑さを追加するだけで、設計の障害の原因を隠すことができます。この場合、障害がバブルアップし、外側のループにキャッチされます。オブジェクトを修復したり、破損としてマークしたり、ロックファイルなどの重要なリソースを解放したり、ソケットをきれいに閉じたりすることができる場合、これは例外の良い使い方です。実際にNULLが有効なエッジケースとして頻繁に現れると予想される場合は、通常のロジックフローでif-the-elseまたはswitch-caseステートメントなどを使用して、例外処理ではなくこれを処理する必要があります。たとえば、フォームで無効になっているフィールドをNULLに設定できます。これは、空白のままになっているフィールドを表す空の文字列とは異なります。これは、適切な判断と常識を使用する必要がある領域です。あらゆる状況でこの問題に対処するための良い経験則を聞いたことがありません。オブジェクトを修復したり、破損としてマークしたり、ロックファイルなどの重要なリソースを解放したり、ソケットをきれいに閉じたりすることができる場合、これは例外の良い使い方です。実際にNULLが有効なエッジケースとして頻繁に現れると予想される場合は、通常のロジックフローでif-the-elseまたはswitch-caseステートメントなどを使用して、例外処理ではなくこれを処理する必要があります。たとえば、フォームで無効になっているフィールドをNULLに設定できます。これは、空白のままになっているフィールドを表す空の文字列とは異なります。これは、適切な判断と常識を使用する必要がある領域です。あらゆる状況でこの問題に対処するための良い経験則を聞いたことがありません。オブジェクトを修復したり、破損としてマークしたり、ロックファイルなどの重要なリソースを解放したり、ソケットをきれいに閉じたりすることができる場合、これは例外の良い使い方です。実際にNULLが有効なエッジケースとして頻繁に現れると予想される場合は、通常のロジックフローでif-the-elseまたはswitch-caseステートメントなどを使用して、例外処理ではなくこれを処理する必要があります。たとえば、フォームで無効になっているフィールドをNULLに設定できます。これは、空白のままになっているフィールドを表す空の文字列とは異なります。これは、適切な判断と常識を使用する必要がある領域です。あらゆる状況でこの問題に対処するための良い経験則を聞いたことがありません。

Javaは、メソッドで使用されるオブジェクトによって発生する可能性のあるすべての例外をメソッドの「スロー」節でキャッチまたは宣言する必要がある「チェック済み例外」で例外処理の実装に失敗します。これは、C ++とPythonの反対で、必要に応じて例外を処理することを選択できます。Javaでは、例外を発生させる可能性のある呼び出しを含めるようにメソッドの本体を変更すると、気にする必要のない例外の明示的な処理を追加する選択に直面するため、コードにノイズと複雑さが追加されます。変更するメソッドの「スロー」句にその例外を追加します。これにより、ノイズと混乱が追加されるだけでなく、メソッドのシグネチャが変更されます。次に、メソッドが使用される可能性のある新しい例外を処理するためにメソッドが使用されている場合は、コードを変更する必要があります。「要件のキャッチまたは指定」は、Javaの最も厄介な側面の1つでなければなりません。RuntimeExceptionsの例外例外と、この設計ミスに対する公式のJavaの合理化は不十分です。

その最後の段落はあなたの質問に答えることとはほとんど関係がありませんでした。私はJavaが嫌いです。

-ノア


この投稿は読みにくい(テキストの壁)。それをより良い形に編集してもいいですか?
gnat
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.