web-dev-qa-db-ja.com

nullの悪いデザインを返していますか?

メソッドから返されたnull値をチェックするのはデザインが悪いと言う声を聞いたことがあります。これにはいくつかの理由があります。

擬似コード:

variable x = object.method()
if (x is null) do something
122
koen

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.
  }
}
196
Adamski

その理由は次のとおりです。

Robert MartinのClean Code では、空の配列を返す代わりに、nullを返すのは悪い設計であると書いています。期待される結果は配列なので、なぜですか?追加の条件なしで結果を反復処理できます。整数の場合は、0で十分かもしれません。ハッシュの場合は空のハッシュです。等.

前提は、呼び出しコードにすぐに問題を処理させることではありません。呼び出し元のコードは、それらに関係することを望まないかもしれません。多くの場合、例外はnilよりも優れている理由でもあります。

67
Max Chernyak

Nullを返すことの良い使用法:

  • Nullが有効な場合、functional result、たとえば:FindFirstObjectThatNeedsProcessing()は、見つからない場合はnullを返すことができ、呼び出し元はそれに応じてチェックする必要があります。

悪用:次のような例外的な状況を置き換えたり、隠そうとすること:

  • catch(...)およびnullを返す
  • API依存関係の初期化に失敗しました
  • ディスク容量不足
  • 無効な入力パラメーター(プログラミングエラー、入力は呼び出し側でサニタイズする必要があります)

これらの場合、次の理由により例外をスローする方が適切です。

  • Nullの戻り値は意味のあるエラー情報を提供しません
  • すぐに呼び出し元がエラー状態を処理できない可能性が高い
  • 呼び出し元がnullの結果をチェックしている保証はありません

ただし、次のような通常のプログラム操作条件を処理するために例外を使用しないでください。

  • 無効なユーザー名/パスワード(またはユーザーが入力したもの)
  • ループの破壊または非ローカルgotoとして
37
ZeroConcept

はい、NULLを返すことは、オブジェクト指向の世界ではひどい設計です。一言で言えば、NULLを使用すると次のようになります。

  • アドホックエラー処理(例外ではなく)
  • あいまいなセマンティック
  • 速く失敗する代わりに遅い
  • オブジェクト思考の代わりにコンピューター思考
  • 可変で不完全なオブジェクト

詳細な説明については、このブログ投稿を確認してください: http://www.yegor256.com/2014/05/13/why-null-is-bad.html 。私の本の詳細 エレガントなオブジェクト 、セクション4.1。

26
yegor256

誰がこれが悪いデザインだと言うのですか?

Nullのチェックは一般的な方法であり、推奨されています。そうしないと、どこでもNullReferenceExceptionsのリスクが発生します。必要のないときに例外をスローするよりも、エラーを適切に処理する方が適切です。

23
Brandon

あなたがこれまでに言ったことに基づいて、私は十分な情報がないと思います。

CreateWidget()メソッドからnullを返すのは悪いようです。

FindFooInBar()メソッドからnullを返すのは問題ないようです。

17
jcollum

その発明者 says それは10億ドルの間違いです!

12
Bahadır Yağan

使用している言語によって異なります。値の欠如を示す慣用的な方法がnullを返すC#のような言語の場合、値がない場合はnullを返すのが良い設計です。あるいは、Haskellなどの、この場合にMaybeモナドを慣用的に使用している言語では、nullを返すのは悪い設計です(可能な場合でも)。

10
Greg Beech

例外は 例外すべての状況。

関数が特定のオブジェクトに関連付けられた属性を見つけることを目的としており、そのオブジェクトにそのような属性がない場合、nullを返すことが適切な場合があります。オブジェクトが存在しない場合は、例外をスローする方が適切な場合があります。関数が属性のリストを返すことを意図しており、返すものがない場合、空のリストを返すことは理にかなっています-あなたはすべてゼロの属性を返します。

3
HyperHacker

私はこの分野でコンベンションを開催してくれました。

単一アイテムクエリの場合:

  • Create...は新しいインスタンスを返しますまたはthrows
  • Get...は、予想される既存のインスタンスを返しますまたはthrows
  • GetOrCreate...は、既存のインスタンスを返します。存在しない場合は新しいインスタンスを返します。またはthrows
  • Find...は、存在する場合は既存のインスタンスを返しますまたはnull

コレクションクエリの場合:

  • Get...は常にコレクションを返します。一致する[1]アイテムが見つからない場合は空です。

[1]明示的または暗黙的ないくつかの基準が与えられ、関数名またはパラメーターとして与えられます。

3
Johann Gerell

何らかの方法で意味がある場合は、nullを返しても構いません。

public String getEmployeeName(int id){ ..}

このような場合、IDが既存のエンティティに対応していない場合はnullを返すことは意味があります。これにより、正当なエラーから一致が見つからなかった場合を区別できます。

エラー状態を示す「特別な」戻り値として悪用される可能性があるため、人々はこれを悪いと考えるかもしれません。エラー状態はあまり良くありません。関数からエラーコードを返すようなものですが、 null、適切な例外をキャッチする代わりに、例えば.

public Integer getId(...){
   try{ ... ; return id; }
   catch(Exception e){ return null;}
}
3
Steve B.

それは必ずしも悪い設計ではありません-多くの設計決定と同様に、それは依存します。

メソッドの結果が通常の使用では良い結果をもたらさないものである場合、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 /* ... */ {
}
3
Michael Burr

特定のシナリオでは、障害が発生するとすぐに通知する必要があります。

NULLをチェックし、失敗の場合にアサート(プログラマーエラーの場合)またはスロー(ユーザーまたは呼び出し元のエラーの場合)しないことは、元の奇妙なケースが見つからなかったため、後のクラッシュを追跡するのが難しくなることを意味します。

さらに、エラーを無視すると、セキュリティ上の悪用につながる可能性があります。おそらく、ヌルが存在するのは、バッファが上書きされたなどの事実によるものです。これで、あなたはnotクラッシュしています。つまり、エクスプロイトはコード内で実行される可能性があります。

2
Drew Hoskins

Nullを返す代替手段はありますか?

次の2つのケースがあります。

  • findAnItem(id)。アイテムが見つからない場合、これはどうすればよいですか

この場合、Nullを返すか、(チェック済み)例外をスローする(または、アイテムを作成して返す)ことができます。

  • listItemsMatching(基準)何も見つからない場合、これは何を返しますか?

この場合、Nullを返すか、空のリストを返すか、例外をスローできます。

Nullを返すことは、クライアントがnullをチェックすることを覚えておく必要があるため、プログラマーが忘れてコードを書く必要があるため、nullを返すことはあまり良いことではないと思います

x = find();
x.getField();  // bang null pointer exception

Javaでは、チェック例外RecordNotFoundExceptionをスローすることにより、コンパイラーはクライアントにケースの処理を促すことができます。

空のリストを返す検索は非常に便利です。リストのすべての内容を表示するだけで、空になります。コードは「機能します」。

2
djna

NULLを返すことが正しい場合もありますが、異なる種類のシーケンス(配列、リスト、文字列、what-have-you)を処理する場合は特に、長さがゼロのシーケンスを返す方がよいでしょう。 APIの実装者側でより多くの記述を行うことなく、より短く、できればより理解しやすいコードになります。

1
Vatine

事実の後に別のメソッドを呼び出して、前の呼び出しがnullであったかどうかを判断させます。 ;-)ねえ、それは JDBCに十分

1
David Plumpton

このスレッドの背後にある基本的な考え方は、防御的にプログラムすることです。つまり、予期しないコードです。さまざまな返信の配列があります。

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

1
GregJF

私のユースケースでは、メソッドからマップを返し、特定のキーを探す必要がありました。ただし、空のMapを返すと、NullPointerExceptionが発生し、空のMapではなくnullを返すことに大きな違いはありません。ただし、Java8以降では Optional を使用できます。上記がオプションの概念が導入されたまさにその理由です。

0
Aman Gupta

コードが次のようなものである場合:

command = get_something_to_do()

if command:  # if not Null
    command.execute()

Execute()メソッドが何も実行しないダミーオブジェクトがあり、適切な場合にNullの代わりにそれを返す場合、Nullケースを確認する必要はなく、代わりに次のようにできます。

get_something_to_do().execute()

したがって、ここでの問題は、NULLをチェックするか例外をチェックするかではなく、代わりに、呼び出し側が特別な非ケースを異なる方法で(何らかの方法で)処理する必要があるかどうかです。

0
Anon

これに対する他のオプションは、成功または失敗(またはエラーのタイプ)を示す値を返しますが、成功/失敗を示すブール値が必要な場合、失敗の場合はnullを返し、成功の場合はオブジェクトを返しませんあまり正確ではない場合、true/falseを返し、パラメータを介してオブジェクトを取得します。
他のアプローチでは、失敗を示すために例外を使用しますが、ここでは、実際にはもっと多くの声があります。
したがって、私は個人的に、何かがうまくいかなかったことを示すものとしてnullを返し、後でそれをチェックすることに何も悪いことはありません(実際に成功したかどうかを知るため)。また、メソッドがNULLを返さないことを盲目的に考えてから、コードをベースにすると、他のエラーが見つかる場合があります(ほとんどの場合、システムがクラッシュするだけです)。 0x00000000遅かれ早かれ)。

0
Marcin Deptuła

意図しないヌル関数は、複雑なプログラムの開発中に発生する可能性があり、デッドコードのように、このような発生はプログラム構造の重大な欠陥を示します。

ヌル関数またはメソッドは、多くの場合、オブジェクトフレームワークの再ベクトル化可能な関数またはオーバーライド可能なメソッドのデフォルトの動作として使用されます。

Null_function @wikipedia

0
Juicy Scripter

まあ、それは確かにメソッドの目的に依存します...時には、より良い選択は例外をスローすることです。それはすべてケースによって異なります。

0
Denis Biondic