これは、中級から中級の開発者がいつか直面する傾向があるかなり一般的な問題のように聞こえます。彼らは、参加している契約を知らないか、信頼していないため、nullを防御的にオーバーチェックしています。さらに、独自のコードを記述する場合、ヌルを返すことに依存して何かを示す傾向があるため、呼び出し側はヌルをチェックする必要があります。
別の言い方をすれば、ヌルチェックが行われる2つの場合があります。
nullは契約に関して有効な応答です。そして
有効な応答ではない場合。
(2)簡単です。assert
ステートメント(アサーション)を使用するか、失敗を許可します(たとえば、 NullPointerException)。アサーションは、1.4で追加された、十分に活用されていないJava機能です。構文は次のとおりです。
assert <condition>
または
assert <condition> : <object>
ここ<condition>
で、はブール式で<object>
あり、toString()
メソッドの出力がエラーに含まれるオブジェクトです。
assert
声明は、スローError
(AssertionError
条件が真でない場合)を。デフォルトでは、Javaはアサーションを無視します。オプション-ea
をJVMに渡すことにより、アサーションを有効にできます。個々のクラスおよびパッケージのアサーションを有効または無効にすることができます。これは、開発およびテスト中にアサーションを使用してコードを検証し、本番環境でそれらを無効にできることを意味しますが、テストではアサーションによるパフォーマンスへの影響はほとんどありません。
この場合、アサーションを使用しなくても問題ありません。これは、コードが失敗するだけです。これは、アサーションを使用した場合に起こります。唯一の違いは、アサーションを使用すると、より意味のある方法で、場合によっては追加の情報を使用して、アサーションが発生する可能性があることです。
(1)少し難しいです。呼び出すコードを制御できない場合は、行き詰まっています。nullが有効な応答である場合は、それを確認する必要があります。
ただし、自分で制御するコードである場合(これはよくあることです)、別の話になります。応答としてnullを使用しないでください。コレクションを返すメソッドを使用すると、簡単です。ほとんどの場合、nullではなく空のコレクション(または配列)を返します。
非コレクションでは、それはより難しいかもしれません。これを例として考えてみましょう:これらのインターフェースがある場合:
public interface Action {
void doSomething();
}
public interface Parser {
Action findAction(String userInput);
}
ここで、Parserは生のユーザー入力を受け取り、何かを実行するためのコマンドラインインターフェイスを実装している場合に、何かを見つけます。ここで、適切なアクションがない場合はnullを返すというコントラクトを作成できます。それはあなたが話しているヌルチェックにつながります。
別の解決策は、nullを返さず、代わりにNullオブジェクトパターンを使用することです。
public class MyParser implements Parser {
private static Action DO_NOTHING = new Action() {
public void doSomething() { /* do nothing */ }
};
public Action findAction(String userInput) {
// ...
if ( /* we can't find any actions */ ) {
return DO_NOTHING;
}
}
}
比較:
Parser parser = ParserFactory.getParser();
if (parser == null) {
// now what?
// this would be an example of where null isn't (or shouldn't be) a valid response
}
Action action = parser.findAction(someInput);
if (action == null) {
// do nothing
} else {
action.doSomething();
}
に
ParserFactory.getParser().findAction(someInput).doSomething();
より簡潔なコードにつながるため、これははるかに優れた設計です。
そうは言っても、おそらくfindAction()メソッドが意味のあるエラーメッセージを伴ってExceptionをスローすることは完全に適切です-特にユーザー入力に依存している場合には。説明のない単純なNullPointerExceptionで呼び出し側のメソッドが爆破するよりも、findActionメソッドが例外をスローする方がはるかに優れています。
try {
ParserFactory.getParser().findAction(someInput).doSomething();
} catch(ActionNotFoundException anfe) {
userConsole.err(anfe.getMessage());
}
または、何もしないのではなく、try / catchメカニズムがあまりにも醜いと思う場合は、デフォルトのアクションでユーザーにフィードバックを提供する必要があります。
public Action findAction(final String userInput) {
/* Code to return requested Action if found */
return new Action() {
public void doSomething() {
userConsole.err("Action not found: " + userInput);
}
}
}