メソッドから返されたnull値をチェックするのは悪い設計だと言う声を聞いたことがあります。その理由を教えてください。
疑似コード:
variable x = object.method()
if (x is null) do something
メソッドから返されたnull値をチェックするのは悪い設計だと言う声を聞いたことがあります。その理由を教えてください。
疑似コード:
variable x = object.method()
if (x is null) do something
回答:
nullを返さない理由は、それをチェックする必要がないため、コードが戻り値に基づいて別のパスをたどる必要がないということです。詳細については、Nullオブジェクトパターンをご覧ください。
たとえば、コレクションを返すJavaでメソッドを定義する場合Collections.emptyList()
、クライアントコードがよりクリーンであることを意味するため、通常はnullではなく空のコレクション(つまり)を返すことを好みます。例えば
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.
}
}
null
は「コンテナ」であり、オブジェクトへのポインタが0または1つ含まれています。(それは確かMaybe
にそれらの場合にHaskellによって明示的にモデル化された方法であり、そうすることにはすべてより良いです。)
これが理由です。
ではロバート・マーティンによってクリーンなコード彼はNULLを返すことはあなたの代わりに、言う、空の配列を返すことができたときに悪いデザインであることを書き込みます。期待される結果は配列なので、なぜですか?追加の条件なしで結果を反復処理できるようになります。整数の場合、0で十分です。ハッシュの場合は、空のハッシュで十分です。等
前提は、問題をすぐに処理するように呼び出しコードを強制しないことです。呼び出し側のコードは、それら自体に関与したくない場合があります。そのため、多くの場合、例外はnilよりも優れています。
nullを返す良い使い方:
悪い使い方:次のような例外的な状況を置き換えたり隠したりすること:
これらの場合、例外をスローする方が適切です。
ただし、次のような通常のプログラム操作条件を処理するために例外を使用しないでください。
boolean login(String,String)
元気そうだし、そうですAuthenticationContext createAuthContext(String,String) throws AuthenticationException
はい、オブジェクト指向の世界では、NULLを返すのはひどい設計です。簡単に言えば、NULLを使用すると、次のようになります。
詳細な説明については、このブログ投稿を確認してください:http : //www.yegor256.com/2014/05/13/why-null-is-bad.html。私の本のエレガントなオブジェクト、セクション4.1の詳細。
bool TryGetBlah(out blah)
またはFirstOrNull()
かMatchOrFallback(T fallbackValue)
。
isEmpty()
、それがtrueの場合にのみメソッドを呼び出します。人々は2番目のものに対してそれはパフォーマンスが悪いと言います-しかし、Unixの哲学が言うように、「人間の時間をマシンの時間よりも重視する」(つまり、パフォーマンスがわずかに遅いのは、開発者が偽のエラーを引き起こしているコードをデバッグするよりも時間を無駄にしません)。
これは悪いデザインだと誰が言いますか?
nullのチェックは一般的な方法であり、推奨されています。それ以外の場合は、どこにでもNullReferenceExceptionsのリスクが発生します。必要のないときに例外をスローするよりも、エラーを適切に処理する方が適切です。
今までの発言から、情報が足りないと思います。
CreateWidget()メソッドからnullを返すのは悪いようです。
FindFooInBar()メソッドからnullを返すのは問題ないようです。
Create...
新しいインスタンスを返すか、スローします。Get...
予期される既存のインスタンスを返すか、またはをスローします。GetOrCreate...
既存のインスタンス、または存在しない場合は新しいインスタンスを返すか、をスローします。Find...
それが存在する場合、既存のインスタンスを返す、またはnull
。コレクションクエリの場合- Get...
常にコレクションを返します。一致するアイテムが見つからない場合は空です。
使用している言語によって異なります。C#のような言語で、値がないことを示す慣用的な方法がnullを返すことである場合、値がない場合はnullを返すことをお勧めします。あるいは、Haskellのような言語で、この場合にMaybeモナドを慣用的に使用している場合、nullを返すのは適切ではありません(可能な場合でも)。
null
C#やJavaなどの言語での定義は、多くの場合、オーバーロードされ、ドメイン内で何らかの意味が与えられています。null
言語仕様でキーワードを検索すると、それは単に「無効なポインタ」を意味します。それはおそらく問題の領域では何も意味しません。
null
か「初期化されていない」のかわからないということですnull
すべての答えを読むと、この質問への答えは方法の種類によって異なります。
まず、例外が発生すると(IOproblemなど)、論理的に例外がスローされます。何かが例外的であるときは、おそらく別のトピックの何かです。
メソッドで結果が得られない可能性があると予想される場合は常に、2つのカテゴリがあります。
関数がnullを返すことができる、またはできないことを示す正式な方法ができるまで、私はそれを示す命名規則を作ろうとしています。失敗することが予想されるメソッドにTry Something()規則
があるのと同じように、メソッドがnullではなくニュートラルな結果を返す場合、私はしばしばメソッドにSafe Something()という名前を付けます。
名前はまだ完全には大丈夫ではありませんが、もっと良いものを思いつくことはできませんでした。それで、今はそれで実行しています。
私はこの領域で私のために役立った大会を持っています
単一アイテムクエリの場合:
Create...
新しいインスタンスを返す、またはスローするGet...
予期される既存のインスタンスを返すか、またはスローしますGetOrCreate...
既存のインスタンス、または存在しない場合は新しいインスタンスを返すか、スローしますFind...
それが存在する場合、既存のインスタンスを返す、またはnull
コレクションクエリの場合:
Get...
常にコレクションを返します。一致する[1]アイテムが見つからない場合は空になります[1]明示的または暗黙的ないくつかの基準が与えられ、関数名またはパラメーターとして与えられます。
Get
にあると予想されるときに使用します。存在しない場合はエラーとなり、スローします。戻り値を確認する必要はありません。あるFind
かどうか本当にわからない場合に使用します。戻り値を確認する必要があります。
例外は例外的な状況のためのものです。
関数が特定のオブジェクトに関連付けられた属性を見つけることを目的としていて、そのオブジェクトにそのような属性がない場合は、nullを返すのが適切な場合があります。オブジェクトが存在しない場合は、例外をスローする方が適切な場合があります。関数が属性のリストを返すことを意図していて、返すものがない場合、空のリストを返すことは理にかなっています-すべてのゼロの属性を返します。
nullを返すことが何らかの意味で意味がある場合は、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 /* ... */ {
}
Optional<>
nullを返す代わりにどのような選択肢がありますか?
私は2つのケースを見ます:
この場合、次のことができます:Nullを返すか、(チェックされた)例外をスローします(または、アイテムを作成してそれを返す可能性があります)
この場合、Nullを返す、空のリストを返す、または例外をスローすることができます。
nullを返すことは、クライアントがnullをチェックすることを覚えておく必要があり、プログラマーが忘れてコードを作成する必要があるため、他の方法よりも優れているとは思わない
x = find();
x.getField(); // bang null pointer exception
Javaでは、チェックされた例外RecordNotFoundExceptionをスローすることで、コンパイラがクライアントに大文字と小文字を処理するように通知できます。
空のリストを返す検索は非常に便利であることがわかりました。リストにすべてのコンテンツを表示するだけで、空で、コードは「機能します」。
このスレッドの背後にある基本的な考え方は、防御的にプログラミングすることです。つまり、予期しないコードに対するコードです。さまざまな返信の配列があります。
Adamskiは、Null Object Patternを検討することを提案し、その回答はその提案に賛成票が投じられました。
Michael Valentyは、何が期待されるかを開発者に伝えるための命名規則も提案しています。 ZeroConceptは、それがNULLの理由である場合、例外の適切な使用を提案します。その他。
防御的プログラミングを常に実行したい「ルール」を作成すると、これらの提案が有効であることがわかります。
ただし、2つの開発シナリオがあります。
開発者が「作成した」クラス:作成者
別の(たぶん)開発者「開発者」が「消費」したクラス
クラスが戻り値を持つメソッドに対してNULLを返すかどうかに関係なく、開発者はオブジェクトが有効かどうかをテストする必要があります。
開発者がこれを実行できない場合、そのクラス/メソッドは確定的ではありません。つまり、オブジェクトを取得するための「メソッド呼び出し」が「アドバタイズ」することを実行しない場合(たとえば、getEmployee)、コントラクトが壊れています。
クラスの作成者として、私はメソッドを作成するときは常に親切で防御的(かつ決定論的)になりたいと思っています。
したがって、NULLまたはNULL OBJECT(たとえば、if(employee as NullEmployee.ISVALID))のいずれかをチェックする必要があり、それがEmployeesのコレクションで発生する必要がある場合、nullオブジェクトアプローチがより良いアプローチです。
しかし、Michael Valentyが nullを返さなければならないメソッドに名前を付けるという提案、たとえばgetEmployeeOrNull も気に入っています。
例外をスローする作成者は、開発者がオブジェクトの有効性をテストする選択肢を取り除きます。これは、オブジェクトのコレクションでは非常に悪いことであり、消費するコードを分岐するときに開発者に例外処理を強制します。
クラスを使用する開発者として、作成者がクラス/メソッドが直面する可能性があるnullの状況を回避またはプログラムする機能を私に与えてくれることを願っています。
開発者として、私はメソッドからNULLに対して防御的にプログラムします。作成者が常にオブジェクトを返す(NULL OBJECTは常に返す)契約を与えており、そのオブジェクトにオブジェクトの有効性をテストするためのメソッド/プロパティがある場合、そのメソッド/プロパティを使用してオブジェクトの使用を継続します、それ以外の場合、オブジェクトは無効であり、使用できません。
結論として、クラス/メソッドの作成者は、開発者が防御プログラミングで使用できるメカニズムを提供する必要があります。つまり、メソッドのより明確な意図。
開発者は常に防御プログラミングを使用して、別のクラス/メソッドから返されたオブジェクトの有効性をテストする必要があります。
よろしく
GregJF
これの他のオプションは次のとおりです。成功または失敗を示す値(またはエラーのタイプ)を返しますが、成功/失敗を示すブール値が必要な場合は、失敗の場合はnullを返し、成功の場合はオブジェクトを返しません。正しくない場合は、true / falseを返し、オブジェクトをパラメーターから取得します。
他のアプローチは例外を使用して失敗を示すことですが、ここに-これは実際にはもっと多くの声があります、これは悪い習慣です(例外を使用することは便利かもしれませんが多くの欠点があるため)。
だから私は個人的に、何かがうまくいかなかったことを示すものとしてnullを返し、後でそれをチェックする(実際に成功したかどうかを知るために)悪いことはありません。また、メソッドがNULLを返さず、コードに基づいていると盲目的に考えると、他の、時には見つけるのが難しいエラーが発生する可能性があります(ほとんどの場合、システムをクラッシュさせるだけです:)。 0x00000000遅かれ早かれ)。
意図しないnull関数は、複雑なプログラムの開発中に発生する可能性があり、デッドコードと同様に、このような発生はプログラム構造に重大な欠陥があることを示しています。
null関数またはメソッドは、オブジェクトフレームワークのリベクトル可能な関数またはオーバーライド可能なメソッドのデフォルトの動作としてよく使用されます。
まあ、それは確かにメソッドの目的に依存します...時には、より良い選択は例外をスローすることでしょう。それはすべてケースごとに異なります。
コードが次のような場合:
command = get_something_to_do()
if command: # if not Null
command.execute()
execute()メソッドが何もしないダミーオブジェクトがあり、適切な場合にNullの代わりにそれを返す場合、Nullケースをチェックする必要はなく、代わりに次のように実行できます。
get_something_to_do().execute()
したがって、ここでの問題は、NULLのチェックと例外の間にあるのではなく、呼び出し側が特別な非大文字小文字を(なんらかの方法で)異なる方法で処理する必要があるかどうかにあります。
G'day、
新しいオブジェクトを作成できないときにNULLを返すことは、多くのAPIの標準的な方法です。
なぜ地獄それが悪いデザインなのか私にはわからない
編集:これは、長年の慣例であるCなどの例外がない言語にも当てはまります。
HTH
「Avahappy、