1. ホーム
  2. java

[解決済み] JavaでNullPointerExceptionを回避する方法

2022-03-14 01:58:03

質問

私が使っているのは object != null を避けるために、多くの場合 NullPointerException .

の代替となるものは何か。

if (someobject != null) {
    someobject.doCalc();
}

解決方法は?

この問題は、中堅から若手の開発者が直面しがちな問題であるように思えます。 さらに、自分自身のコードを書くとき、彼らは何かを示すためにnullを返すことに依存しがちで、その結果、呼び出し側がnullをチェックする必要があります。

つまり、NULLチェックが発生するケースは2つあるのです。

  1. nullが契約上、有効なレスポンスである場合。

  2. 有効な回答でない場合。

(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を決して返さず、代わりに Null Objectパターン :

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メソッドがExceptionを投げる方がずっといいでしょう。

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);
        }
    }
}