nullをチェックする必要がない場合のガイドラインは何ですか?
私が最近取り組んできた継承されたコードの多くは、nullチェックと悪意を持っています。些細な関数のnullチェック、null以外の戻り値を示すAPI呼び出しのnullチェックなど。場合によっては、nullチェックは妥当ですが、多くの場合、nullは妥当な期待ではありません。
「他のコードを信頼できない」から「常に防御的にプログラムする」、「言語がnull以外の値を保証するまで、常にチェックする」など、さまざまな議論を聞いています。私は確かにこれらの原則の多くにある程度同意しますが、過度のnullチェックは、通常これらの原則に違反する他の問題を引き起こすことがわかりました。粘り強いヌルチェックは本当に価値がありますか?
頻繁に、過剰なnullチェックを含むコードは、実際には高品質ではなく、低品質であることがわかりました。コードの多くはnullチェックに重点を置いているため、開発者は読みやすさ、正確さ、例外処理などの他の重要な品質を見失っています。特に、多くのコードがstd :: bad_alloc例外を無視しているのがわかりますが、。に対してnullチェックを実行しますnew
。
C ++では、nullポインターを逆参照するという予測できない動作のために、これをある程度理解しています。null逆参照は、Java、C#、Pythonなどでより適切に処理されます。注意深いnullチェックの悪い例を見たことがありますか、それとも本当に何かありますか?
私は主にC++、Java、およびC#に関心がありますが、この質問は言語に依存しないことを目的としています。
過剰に見えるヌルチェックの例には、次のものがあります。
この例では、C ++仕様では、失敗したnewが例外をスローすると述べているため、非標準のコンパイラを考慮しているようです。非準拠のコンパイラを明示的にサポートしていない限り、これは意味がありますか?これは、JavaやC#(またはC ++ / CLR)のような管理された言語では意味がありますか?
try {
MyObject* obj = new MyObject();
if(obj!=NULL) {
//do something
} else {
//??? most code I see has log-it and move on
//or it repeats what's in the exception handler
}
} catch(std::bad_alloc) {
//Do something? normally--this code is wrong as it allocates
//more memory and will likely fail, such as writing to a log file.
}
もう1つの例は、内部コードで作業する場合です。特に、独自の開発手法を定義できる小さなチームの場合、これは不要のようです。一部のプロジェクトやレガシーコードでは、ドキュメントを信頼することは合理的ではないかもしれません...しかし、あなたやあなたのチームが管理する新しいコードの場合、これは本当に必要ですか?
表示して更新できる(または責任のある開発者に怒鳴ることができる)メソッドにコントラクトがある場合でも、nullをチェックする必要がありますか?
//X is non-negative.
//Returns an object or throws exception.
MyObject* create(int x) {
if(x<0) throw;
return new MyObject();
}
try {
MyObject* x = create(unknownVar);
if(x!=null) {
//is this null check really necessary?
}
} catch {
//do something
}
プライベート関数またはその他の内部関数を開発する場合、コントラクトがnull以外の値のみを要求する場合、nullを明示的に処理する必要が本当にありますか?なぜアサーションよりもヌルチェックの方が望ましいのでしょうか?
(明らかに、パブリックAPIでは、APIを誤って使用したことでユーザーに怒鳴るのは失礼だと考えられているため、ヌルチェックは不可欠です)
//Internal use only--non-public, not part of public API
//input must be non-null.
//returns non-negative value, or -1 if failed
int ParseType(String input) {
if(input==null) return -1;
//do something magic
return value;
}
に比べ:
//Internal use only--non-public, not part of public API
//input must be non-null.
//returns non-negative value
int ParseType(String input) {
assert(input!=null : "Input must be non-null.");
//do something magic
return value;
}