メソッドから返されたnull値をチェックするのはデザインが悪いと言う声を聞いたことがあります。これにはいくつかの理由があります。
擬似コード:
variable x = object.method()
if (x is null) do something
Nullを返さない理由は、nullをチェックする必要がないため、コードはリターンに基づいて異なるパスをたどる必要がないことです。値。 Null Object Pattern を確認すると、詳細がわかります。
たとえば、コレクションを返すJavaでメソッドを定義する場合、通常はnullではなく空のコレクション(つまりCollections.emptyList()
)を返すことを意味します私のクライアントコードはきれいです;例えば.
Collection<? extends Item> c = getItems(); // Will never return null.
for (Item item : c) { // Will not enter the loop if c is empty.
// Process item.
}
...これは次のものよりもきれいです。
Collection<? extends Item> c = getItems(); // Could potentially return null.
// Two possible code paths now so harder to test.
if (c != null) {
for (Item item : c) {
// Process item.
}
}
その理由は次のとおりです。
Robert MartinのClean Code では、空の配列を返す代わりに、nullを返すのは悪い設計であると書いています。期待される結果は配列なので、なぜですか?追加の条件なしで結果を反復処理できます。整数の場合は、0で十分かもしれません。ハッシュの場合は空のハッシュです。等.
前提は、呼び出しコードにすぐに問題を処理させることではありません。呼び出し元のコードは、それらに関係することを望まないかもしれません。多くの場合、例外はnilよりも優れている理由でもあります。
Nullを返すことの良い使用法:
悪用:次のような例外的な状況を置き換えたり、隠そうとすること:
これらの場合、次の理由により例外をスローする方が適切です。
ただし、次のような通常のプログラム操作条件を処理するために例外を使用しないでください。
はい、NULLを返すことは、オブジェクト指向の世界ではひどい設計です。一言で言えば、NULLを使用すると次のようになります。
詳細な説明については、このブログ投稿を確認してください: http://www.yegor256.com/2014/05/13/why-null-is-bad.html 。私の本の詳細 エレガントなオブジェクト 、セクション4.1。
誰がこれが悪いデザインだと言うのですか?
Nullのチェックは一般的な方法であり、推奨されています。そうしないと、どこでもNullReferenceExceptionsのリスクが発生します。必要のないときに例外をスローするよりも、エラーを適切に処理する方が適切です。
あなたがこれまでに言ったことに基づいて、私は十分な情報がないと思います。
CreateWidget()メソッドからnullを返すのは悪いようです。
FindFooInBar()メソッドからnullを返すのは問題ないようです。
その発明者 says それは10億ドルの間違いです!
使用している言語によって異なります。値の欠如を示す慣用的な方法がnullを返すC#のような言語の場合、値がない場合はnullを返すのが良い設計です。あるいは、Haskellなどの、この場合にMaybeモナドを慣用的に使用している言語では、nullを返すのは悪い設計です(可能な場合でも)。
例外は 例外すべての状況。
関数が特定のオブジェクトに関連付けられた属性を見つけることを目的としており、そのオブジェクトにそのような属性がない場合、nullを返すことが適切な場合があります。オブジェクトが存在しない場合は、例外をスローする方が適切な場合があります。関数が属性のリストを返すことを意図しており、返すものがない場合、空のリストを返すことは理にかなっています-あなたはすべてゼロの属性を返します。
私はこの分野でコンベンションを開催してくれました。
単一アイテムクエリの場合:
Create...
は新しいインスタンスを返しますまたはthrowsGet...
は、予想される既存のインスタンスを返しますまたはthrowsGetOrCreate...
は、既存のインスタンスを返します。存在しない場合は新しいインスタンスを返します。またはthrowsFind...
は、存在する場合は既存のインスタンスを返しますまたはnull
コレクションクエリの場合:
Get...
は常にコレクションを返します。一致する[1]アイテムが見つからない場合は空です。[1]明示的または暗黙的ないくつかの基準が与えられ、関数名またはパラメーターとして与えられます。
何らかの方法で意味がある場合は、nullを返しても構いません。
public String getEmployeeName(int id){ ..}
このような場合、IDが既存のエンティティに対応していない場合はnullを返すことは意味があります。これにより、正当なエラーから一致が見つからなかった場合を区別できます。
エラー状態を示す「特別な」戻り値として悪用される可能性があるため、人々はこれを悪いと考えるかもしれません。エラー状態はあまり良くありません。関数からエラーコードを返すようなものですが、 null、適切な例外をキャッチする代わりに、例えば.
public Integer getId(...){
try{ ... ; return id; }
catch(Exception e){ return null;}
}
それは必ずしも悪い設計ではありません-多くの設計決定と同様に、それは依存します。
メソッドの結果が通常の使用では良い結果をもたらさないものである場合、nullを返すことは問題ありません。
object x = GetObjectFromCache(); // return null if it's not in the cache
常に常に非nullの結果が必要な場合は、例外をスローする方が良い場合があります。
try {
Controller c = GetController(); // the controller object is central to
// the application. If we don't get one,
// we're fubar
// it's likely that it's OK to not have the try/catch since you won't
// be able to really handle the problem here
}
catch /* ... */ {
}
特定のシナリオでは、障害が発生するとすぐに通知する必要があります。
NULLをチェックし、失敗の場合にアサート(プログラマーエラーの場合)またはスロー(ユーザーまたは呼び出し元のエラーの場合)しないことは、元の奇妙なケースが見つからなかったため、後のクラッシュを追跡するのが難しくなることを意味します。
さらに、エラーを無視すると、セキュリティ上の悪用につながる可能性があります。おそらく、ヌルが存在するのは、バッファが上書きされたなどの事実によるものです。これで、あなたはnotクラッシュしています。つまり、エクスプロイトはコード内で実行される可能性があります。
Nullを返す代替手段はありますか?
次の2つのケースがあります。
この場合、Nullを返すか、(チェック済み)例外をスローする(または、アイテムを作成して返す)ことができます。
この場合、Nullを返すか、空のリストを返すか、例外をスローできます。
Nullを返すことは、クライアントがnullをチェックすることを覚えておく必要があるため、プログラマーが忘れてコードを書く必要があるため、nullを返すことはあまり良いことではないと思います
x = find();
x.getField(); // bang null pointer exception
Javaでは、チェック例外RecordNotFoundExceptionをスローすることにより、コンパイラーはクライアントにケースの処理を促すことができます。
空のリストを返す検索は非常に便利です。リストのすべての内容を表示するだけで、空になります。コードは「機能します」。
NULLを返すことが正しい場合もありますが、異なる種類のシーケンス(配列、リスト、文字列、what-have-you)を処理する場合は特に、長さがゼロのシーケンスを返す方がよいでしょう。 APIの実装者側でより多くの記述を行うことなく、より短く、できればより理解しやすいコードになります。
事実の後に別のメソッドを呼び出して、前の呼び出しがnullであったかどうかを判断させます。 ;-)ねえ、それは JDBCに十分
このスレッドの背後にある基本的な考え方は、防御的にプログラムすることです。つまり、予期しないコードです。さまざまな返信の配列があります。
Adamskiは、Null Object Patternを調べることを提案し、その提案に対してその回答が賛成票を投じられます。
Michael Valentyは、開発者に期待されることを伝えるための命名規則も提案しています。 ZeroConceptは、それがNULLの理由である場合、例外の適切な使用を提案します。その他。
常に防御的なプログラミングを行いたい「ルール」を作成すると、これらの提案が有効であることがわかります。
しかし、2つの開発シナリオがあります。
開発者によって「作成された」クラス:著者
別の(おそらく)開発者によって「消費される」クラス:開発者
クラスが戻り値を持つメソッドに対してNULLを返すかどうかに関係なく、開発者はオブジェクトが有効かどうかをテストする必要があります。
開発者がこれを行えない場合、そのクラス/メソッドは決定論的ではありません。つまり、オブジェクトを取得するための「メソッド呼び出し」が「アドバタイズ」すること(getEmployeeなど)を実行しない場合、コントラクトが壊れています。
クラスの作成者として、メソッドを作成するときは常に親切で防御的(かつ決定論的)になりたいと思っています。
したがって、NULLまたはNULL OBJECT(if(employee as NullEmployee.ISVALID))のいずれかをチェックする必要があり、それがEmployeesのコレクションで発生する必要がある場合、nullオブジェクトアプローチがより良いアプローチです。
しかし、私はMichael Valenty's nullを返さなければならないメソッド、たとえばgetEmployeeOrNullの命名の提案も気に入っています。
例外をスローするAuthorは、オブジェクトの有効性をテストする開発者の選択を削除します。これは、オブジェクトのコレクションでは非常に悪いことであり、開発者に消費コードの分岐時に例外処理を強制します。
クラスを使用する開発者として、著者がクラス/メソッドが直面する可能性のあるヌルの状況を回避またはプログラミングできるようにしてくれることを願っています。
開発者として、メソッドからのNULLに対して防御的にプログラムします。作成者がオブジェクトを常に返すコントラクト(NULLオブジェクトは常に行う)を提供し、そのオブジェクトにオブジェクトの有効性をテストするメソッド/プロパティがある場合、そのメソッド/プロパティを使用してオブジェクトの使用を継続します、それ以外の場合、オブジェクトは無効であり、使用できません。
結論として、クラス/メソッドの作成者は、開発者が防御的なプログラミングで使用できるメカニズムを提供する必要があります。つまり、メソッドの明確な意図。
開発者は、常に防御プログラミングを使用して、別のクラス/メソッドから返されたオブジェクトの有効性をテストする必要があります。
よろしく
GregJF
私のユースケースでは、メソッドからマップを返し、特定のキーを探す必要がありました。ただし、空のMapを返すと、NullPointerExceptionが発生し、空のMapではなくnullを返すことに大きな違いはありません。ただし、Java8以降では Optional を使用できます。上記がオプションの概念が導入されたまさにその理由です。
コードが次のようなものである場合:
command = get_something_to_do()
if command: # if not Null
command.execute()
Execute()メソッドが何も実行しないダミーオブジェクトがあり、適切な場合にNullの代わりにそれを返す場合、Nullケースを確認する必要はなく、代わりに次のようにできます。
get_something_to_do().execute()
したがって、ここでの問題は、NULLをチェックするか例外をチェックするかではなく、代わりに、呼び出し側が特別な非ケースを異なる方法で(何らかの方法で)処理する必要があるかどうかです。
これに対する他のオプションは、成功または失敗(またはエラーのタイプ)を示す値を返しますが、成功/失敗を示すブール値が必要な場合、失敗の場合はnullを返し、成功の場合はオブジェクトを返しませんあまり正確ではない場合、true/falseを返し、パラメータを介してオブジェクトを取得します。
他のアプローチでは、失敗を示すために例外を使用しますが、ここでは、実際にはもっと多くの声があります。
したがって、私は個人的に、何かがうまくいかなかったことを示すものとしてnullを返し、後でそれをチェックすることに何も悪いことはありません(実際に成功したかどうかを知るため)。また、メソッドがNULLを返さないことを盲目的に考えてから、コードをベースにすると、他のエラーが見つかる場合があります(ほとんどの場合、システムがクラッシュするだけです)。 0x00000000遅かれ早かれ)。
意図しないヌル関数は、複雑なプログラムの開発中に発生する可能性があり、デッドコードのように、このような発生はプログラム構造の重大な欠陥を示します。
ヌル関数またはメソッドは、多くの場合、オブジェクトフレームワークの再ベクトル化可能な関数またはオーバーライド可能なメソッドのデフォルトの動作として使用されます。
まあ、それは確かにメソッドの目的に依存します...時には、より良い選択は例外をスローすることです。それはすべてケースによって異なります。