web-dev-qa-db-ja.com

nullまたは空の値を返す/例外をスローしますか?

さまざまなプログラミングブックでは、メソッドはnull値(たとえば、クリーンコード)を返すべきではないと示唆しています。 nullを返す代わりに、デフォルト値(0または空の文字列または空のオブジェクト)を返すか、例外をスローする必要があります。これは、多くの_!= null_チェックを回避するため、またはNullPointerExceptionを回避するために推奨されます。

これがどのように役立つか私には本当にわかりません。デフォルト値を返す場合は、_!= DEFAULT_チェックを行う必要があります。さらに、デフォルト値は何かを意味する場合があります(クレジット金額の0など)。特定の例外をスローすることは価値がありません。コードを適切に処理しないと、とにかく例外がスローされるためです-NullPointerException

nullを返すのではなく、空のオブジェクト(例:new MyBean())を返すメソッドが原因のバグを見つけたとき、私はこれについて考えました。コードは機能せず、ログは何も警告しなかったため、検出と修正はそれほど簡単ではありませんでした。 nullを指定すると、NullPointerExceptionがスローされるので、バグを見つけて修正するのは簡単です。

nullを返す代わりにデフォルト値を返すことが私にとって意味のある唯一のケースは、配列/コレクションを返すときです。ここでは通常_for each element in collection_が消費されるため、空の場合は何も起こりませんが、それがnullの場合はNPEがスローされます。

10
m3th0dman

さまざまなプログラミングブックでは、メソッドはnull値を返すべきではないと示唆しています(たとえば、クリーンコード)。 nullのデフォルト値(0または空の文字列または空のオブジェクト)を返す代わりに、例外をスローする必要があります。これは、多くの!= nullチェックを回避するため、またはNullPointerExceptionを回避するために推奨されます。

マーティン氏は、あなたがalways例外をスローし、neverエラー値を返すべきだと主張しなかったことは、言及する価値があり、一般的な誤解です。実際、注意深く読んだ場合、関連する文章はかなり異なります(ここには英語版がないので、翻訳して戻す必要があります)。

nullポインターを返す場合は、代わりに例外をスローすることを検討してください。

consider」とあり、「thou shalt」ではないことに注意してください。

もう1つは、次の2つです。


PS:私のドイツ語版の原文:

Wenn Sie versucht sind、einen Nullzeiger zu liefern、sollten Sie stattdessenerwägen、eine Exception zu werfen。

11
JensG

私の意見では、単一の値を返すメソッドの場合、nullは、型の空またはデフォルトのインスタンスを返すよりもはるかに優れています。デフォルト値はエラーをマスクするだけでなく、タイプの複雑さに応じて、APIプロデューサーとAPIコンシューマーが誤った結果を表す値/値に関する一貫した概念を維持する必要があるため、メソッド間の複雑な依存関係を文書化することができます。

一方、コレクションの場合、空のコレクションを返す方がnullを返すよりもはるかに優れています。これは、メソッドの呼び出し元が期待する結果の数が可変であり、空のコレクションが概念的に有効であることを示しているためです。結果であり、数学の空集合の概念と対称です。

ただし、特にメソッドがvoidまたはunitを返す場合は、例外があります。

4
Aluan Haddad

エラー状態が発生することが予想される方法と発生しない方法を区別することは非常に重要です。その方法の契約について明確に理解することも同様に重要です。

メソッドが定期的に障害に遭遇する(データベースからデータを取得するなど)場合、成功/失敗を返す方法とデータを返す方法が必要です。私の好みは通常、操作に対してtrue/falseを返すことです。別の呼び出しを使用してデータやステータスを取得します。

メソッドがエラーの発生が予想されないものである場合(インデックスからコレクションからアイテムを返すなど)、メソッドはneverがnullを返す必要があります。有効なアイテムを返すか、例外を発生させるか、アサートする必要があります。呼び出し元は、返される結果を常に有効にするため、neverで結果を確認する必要があります。

アサートではなくデフォルト値を返す方が便利な場合がありますが、これはメソッドコントラクトに反映される必要があり、2つのメソッド(GetXxxおよびGetXxxOrDefault)が存在する可能性があります。

Nullに対する戻り値の広範囲にわたるチェックは、多くの場合、コードのより深い問題の兆候です。最近のプログラミング本にあるアドバイスは確かです。


コメントに応じて、ルックアップ、計算、解析などを実行するためにメソッドが必要であり、失敗が日常的に発生する場合を検討してください。例外とTryParse()フォームはコードのフローを壊すので、私は嫌いです。一方、デフォルトが正当な戻り値である場合、FindOrDefault()フォームは苦痛です。私はこのラッパーを好む傾向があります:

public static U SafeLookup<T, U>(this Dictionary<T, U> dict, T key, U missing = default(U)) {
  U ret;
  if (dict.TryGetValue(key, out ret)) return ret;
  return missing;
}

常に値が返され、エラー時に返す値をオプションで指定できます。

2
david.pfx

nullやその他のエラー値を返すのではなく、例外をスローするのが好きです。特定の形式のXMLを解析する新しいクラスを設計しているとしましょう。クラスのエントリポイントを1つだけ、つまり有効なXMLファイルへのパスを指定するコンストラクターにしたいと考えています。代わりに、XMLファイルのコンテンツを保持し、それに関する情報を提供する一連のプロパティとメソッドを持つオブジェクトを取得します。

たとえば、XMLファイルへのパスが有効であることをどのように確認できますか?たとえば、クラスにLoad(string xmlPath)関数を含めることができます。戻り値の型は何ですか? boolまたはintまたは何を返す必要がありますか?そして、最も興味深いのは、それをどのように確認できるでしょうか?理想的には、Load関数をprivateにし、それが存在することさえ気にしないでください。しかし、Loadの結果を確認したい場合は、関数をpublicにする必要があります。または、_bool loadSuccesful_変数をコンストラクターに渡し、ファイルをロードした結果をそのコンストラクターに入力します。しかし、待って、XMLファイルをXSDに対してチェックしたい場合はどうなりますか?別の関数parseXmlSchema(string xmlPath)またはそのようなものを用意する必要があります。失敗した場合、何を返す必要がありますか?そして、どのようにすれば、クリーンなインターフェースを維持しながら、クラスから情報を取得できますか?他の検証も必要になる可能性があります。

一方、これらの種類のメソッドをプライベートにして、何かがうまくいかない場合に例外をスローすると(XMLファイルが有効でない場合、実際に解析しても意味がありません)、クリーンなインターフェイスを使用して_try/catch_ステートメント。 stringパラメーターを1つだけ(またはXSDスキーマを数える場合は2つ)のクラスコンストラクターを作成できます。すべてがtryステートメントで問題がなければ、何も問題がなければ、例外はスローされず、パスが存在するなど、プログラムは問題ありません。現在アプリの中間層にいて、下位層からFileNotFoundExceptionを取得している場合は、それをrethrowしてユーザー(GUI)に渡し、何かを行うことができます。 GUIレイヤーはこの時点でそれをキャッチし、たとえばmessageBoxを介してユーザーに警告し、ボーナスとしてログに記録できます。次に、ユーザーは別のXMLファイルを試し、次に話を進めます。可能性のあるすべての例外をキャッチし、意味のある情報をユーザーに表示するか、バックグラウンドで適切な対策を講じれば、アプリケーションがフリーズする必要はありません(恐らくそれが見られます)。

おまけとして、例外がスローされた時点で、メッセージ、パラメーター名、行番号、関数名など、あらゆる種類の意味のある情報を渡すことができます。コードを文書化する場合(必要に応じて)、例外を文書化します。クラス/メソッドはスローできます。

1
mihai