すべてのロジックがメソッドのパラメーターを反復するforeachループ内で実行されるメソッドがあります。
public IEnumerable<TransformedNode> TransformNodes(IEnumerable<Node> nodes)
{
foreach(var node in nodes)
{
// yadda yadda yadda
yield return transformedNode;
}
}
この場合、空のコレクションを送信すると空のコレクションになりますが、それが賢明ではないかと思います。
ここでの私の論理は、誰かがこのメソッドを呼び出している場合、データを渡すつもりであり、誤った状況では空のコレクションを私のメソッドにのみ渡すということです。
この動作をキャッチして例外をスローする必要がありますか、それとも空のコレクションを返すのがベストプラクティスですか?
ユーティリティメソッドは空のコレクションをスローするべきではありません。 APIクライアントはそれを嫌います。
コレクションは空にすることができます。 「空にする必要のないコレクション」は、概念的には操作がはるかに困難です。
空のコレクションの変換には明らかな結果があります。空のコレクションです。 (パラメーター自体を返すことで、ガベージを節約することもできます。)
モジュールが、すでに何かで満たされているかどうかわからないもののリストを維持する多くの状況があります。 transform
を呼び出す前に毎回空をチェックする必要があるのは面倒で、シンプルでエレガントなアルゴリズムを醜い混乱に変える可能性があります。
ユーティリティメソッドは常に、入力ではリベラルであり、出力では保守的であるように努力する必要があります。
これらすべての理由から、神のために、空のコレクションを正しく処理します。 考えるそれはあなたが何をしたいかよりもあなたが何が欲しいかを知っているヘルパーモジュールほど苛立たしいものはありません。
これに対する答えを決定する2つの重要な質問が表示されます。
1。意味のあるリターン
基本的に、意味のあるものを返すことができる場合は、例外をスローしないでください。発信者に結果を処理させます。だからあなたの機能...
一般に、my FPバイアスは「意味のある何かを返す」ことを示し、nullはこの場合有効な意味を持つことができます。
2。スタイル
一般的なコード(またはプロジェクトのコードまたはチームのコード)は、機能的なスタイルを支持していますか?いいえの場合、例外が予想され、処理されます。はいの場合、 オプションの種類 を返すことを検討してください。オプションタイプでは、意味のある答えを返すか、None/Nothingを返します。上記の3番目の例では、NothingがFPスタイルで適切な答えになります。関数が返す事実Optionタイプは、意味のある回答が不可能である可能性があることを発信者に明確に知らせ、発信者はそれに対処する準備をする必要があることを通知します。
F#は、すべてのクールな.Net子供がこの種のことを行う場所ですが、C#が行うsupport このスタイルです。
tl; dr
予期しないエラーの例外は、自分のコードパスで保持してください。他人からの予測可能な(そして合法的な)入力ではありません。
相変わらず、それは依存します。
matterコレクションは空ですか?
ほとんどのコレクション処理コードはおそらく「ノー」と言うでしょう。コレクションには任意の数のアイテムを含めることができます含むゼロ。
さて、中にアイテムがないことが「無効」であるようなコレクションがある場合、それは新しい要件であり、それに対して何をするかを決定する必要があります。
データベースの世界からいくつかのテストロジックを借用します:zero items、one itemおよびtwo itemsのテスト。これは、最も重要なケース(不適切な形式の内部結合またはデカルト結合の条件をすべて洗い流す)に対応します。
優れた設計の問題として、入力の変動をできるだけ実用的または可能な限り受け入れます。例外はonlyがスローされる必要があります(許容できない入力が提示されたOR処理中に予期しないエラーが発生した)ANDプログラムは予測可能な方法で続行できません結果として。
この場合、空のコレクションが表示され、コードはそれを処理する必要があります(すでに処理されています)。コードがここで例外をスローした場合、それはすべての違反になります。これは、数学で0を0で乗算するようなものです。これは冗長ですが、動作するためには絶対に必要です。
次に、nullコレクション引数に移ります。この場合、nullコレクションはプログラミングの誤りです。プログラマーが変数を割り当てるのを忘れていました。これは例外をスローする可能性のあるケースです。例外を出力に有意義に処理できず、そうしようとすると予期しない動作が発生します。これは数学でゼロで割ることに似ています-それは完全に無意味です。
関数を単独で見ているだけでは、正しい解決策を見つけるのははるかに困難です。関数を より大きな問題 の一部と見なしてください。その例の1つの可能な解決策は次のようになります(Scalaの場合):
_input.split("\\D")
.filterNot (_.isEmpty)
.map (_.toInt)
.filter (x => x >= 1000 && x <= 9999)
_
最初に、文字列を非数字で分割し、空の文字列をフィルターで除外し、文字列を整数に変換してから、4桁の数字のみを保持するようにフィルターします。あなたの関数はパイプラインのmap (_.toInt)
かもしれません。
パイプラインの各ステージは空の文字列または空のコレクションを処理するだけなので、このコードはかなり単純です。最初に空の文字列を入れると、最後に空のリストが表示されます。すべての呼び出しの後にnull
または例外を停止して確認する必要はありません。
もちろん、これは空の出力リストが複数の意味を持たないことを前提としています。空の入力が原因の空の出力と変換自体が原因の出力を区別する必要がある必要がある場合は、状況を完全に変更します。
この質問は実際には例外についてです。そのように見て、実装の詳細として空のコレクションを無視すると、答えは簡単です:
1)続行できない場合、メソッドは例外をスローする必要があります。指定されたタスクを実行できないか、適切な値を返します。
2)メソッドは、失敗にもかかわらず続行できる場合、例外をキャッチする必要があります。
したがって、ヘルパーメソッドは「役立つ」べきではなく、itが空のコレクションでの作業を実行できない場合を除き、例外をスローします。呼び出し元に、結果を処理できるかどうかを判断させます。
空のコレクションを返すかnullを返すかは少し難しいですが、それほど多くはありません。null可能なコレクションは、可能であれば避けてください。 null可能なコレクションの目的は、(SQLのように)情報がないことを示すことです-たとえば、誰かが持っているかどうかはわからないが、あなたが知らない場合、子のコレクションはnullになる可能性があります。彼らが知らないことを知っています。しかし、それが何らかの理由で重要である場合、それを追跡するために追加の変数を使用する価値があります。
メソッドの名前はTransformNodes
です。空のコレクションを入力として使用する場合、空のコレクションを取得するのは自然で直感的であり、数学的には非常に理にかなっています。
メソッドの名前がMax
で、最大の要素を返すように設計されている場合、空のコレクションに対してNoSuchElementException
をスローするのは自然なことです。
メソッドの名前がJoinSqlColumnNames
で、SQLクエリで使用するために要素がコンマで結合されている文字列を返すように設計されている場合、空のコレクションでIllegalArgumentException
をスローするのは理にかなっています。呼び出し側は、さらにチェックせずにSQLクエリで文字列を直接使用し、返された空の文字列をチェックする代わりに、空のコレクションを実際にチェックする必要がある場合、最終的にSQLエラーが発生します。
一歩下がって、値の配列の算術平均を計算する別の例を使用してみましょう。
入力配列が空(またはnull)の場合、呼び出し元の要求を合理的に満たすことができますか?いいえ。あなたのオプションは何ですか?さて、あなたはできる:
無効な入力があり、リクエストを完了できない場合は、エラーを表示すると言います。プログラムの要件を理解してもらうために、初日からのハードエラーを意味します。結局のところ、関数は応答する立場にありません。操作couldが失敗した場合(ファイルのコピーなど)、APIは処理できるエラーを提供する必要があります。
これにより、ライブラリが不正なリクエストや失敗する可能性のあるリクエストを処理する方法を定義できます。
コードがこれらのクラスのエラーを処理する方法に一貫性があることは非常に重要です。
次のカテゴリは、ライブラリがナンセンスリクエストを処理する方法を決定することです。あなたに似た例に戻りましょう-パスにファイルが存在するかどうかを判別する関数を使用してみましょう:bool FileExistsAtPath(String)
。クライアントが空の文字列を渡す場合、このシナリオをどのように処理しますか? void SaveDocuments(Array<Document>)
に渡される空またはnullの配列はどうですか?ライブラリ/コードベースを決定し、一貫性がある。私はたまたまこれらのケースのエラーを考慮し、クライアントにエラーとしてフラグを立てることによって(アサーションを介して)ナンセンスなリクエストを行うことを禁止します。一部の人々はその考え/行動に強く抵抗します。このエラー検出は非常に役立ちます。問題のあるプログラムへの局所性が高いため、プログラム内の問題を特定するのに非常に適しています。プログラムはより明確で正確であり(コードベースの進化を考慮して)、何もしない関数内でサイクルを焼き付けないでください。コードはこのように小さく/きれいになり、チェックは通常、問題が発生する可能性のある場所にプッシュされます。