JavaマスターJavaプログラムサンプル集例外のサンプル → NullPointerException 対策(その4)

NullPointerException 対策(その4)

コンストラクタを使うことにより、 安全性の高く(NullPointerExceptionが発生しない)、 利用する場合にも使いやすいクラスを作ることができます。

C : 例外が起こりえない設計を行う

A と B の例は、Personオブジェクトのnameフィールドがnullかもしれないということを 想定して、事前にチェックしたり、事後に例外をキャッチしたりしていました。 しかし、もし、nameフィールドに必ず何らかの文字列がセットされる(つまり、絶対にnullになることがない) ということがわかっていれば、チェックや例外処理を省くことができるのです。

具体的には、Personクラスを以下のように変更します。

samples/exception/nullpointer/Person2.java - Eclipse SDK
package samples.exception.nullpointer;

public class Person2 {
  private String name;

  public Person2(String name) {
    setName(name);
  }
  
  public Person2() {
    this(null);
  }
  
  public String getName() {
    return name;
  }

  public void setName(String name) {
    if (name == null) {
      // 引数がnullの場合は、デフォルト値をセットします。
      // ここでは、デフォルト値を「長さ0の文字列」とします。
      this.name = "";
    else {
      // 引数がnullではなく文字列の場合は、
      // それをセットします。
      this.name = name;
    }
  }
}

Personクラスと同じようにnameフィールドを持つ、Person2というクラスを作成しました。

まず、setNameというメソッドを見てください。 このメソッドは、nameフィールドに新しい値をセットするためのメソッドです。 このメソッドにおいて、引数nameの値を、フィールドnameにセットするわけですが、 その際に引数のチェックを行い、nullの場合は「""」という文字列 (文字を1文字も持たない、長さが0の文字列)を セットするようにしています。

次に、Person2のコンストラクタを見てください。

1つめのコンストラクタ「Person2(String name)」では、引数にて名前の文字列を 受け取り、その名前データをsetNameメソッドにてセットしています。 ですから、仮に、「Person2(null)」のようにしてPerson2オブジェクトを作成したとしても、 setNameメソッドの働きにより、name列にnullがセットされることはありません。

2つめのコンストラクタ「Person2()」では、1つめのコンストラクタを呼び出しています。 このコンストラクタを準備しておくことによって、このクラスを使うときに、名前データを指定しなくても オブジェクトが作れるのです。しかも、その場合でも、name列にはnullは入りません。

これらのコンストラクタの働きにより、このPerson2クラスのオブジェクトは、必ず nullではない氏名の文字列を持った状態で作成されることが保障されます。

最後に、nameフィールドのアクセス制限を、privateとしています。 これにより、Person2クラスの外部からは、 nameフィールドに対して勝手に新しい値やnullをセットすることができなくなります。 つまり、nameフィールドを変更できるのが、間違いなくPerson2クラス 自身だけであるという状態を作ることができます。

以上の仕組みにより、Person2のオブジェクトのnameフィールドがnullにならないことが保障されます。

なお、nameフィールドをprivateアクセス制限としたので、 もはや 外部からp.nameのようにして フィールドを読み取ることはできなくなっています。 そこで、nameフィールドの値を取得するためのgetNameメソッドも 追加しています。

以下は、Person2クラスを実際に使ってみる例です。

samples/exception/nullpointer/NullPointer5.java - Eclipse SDK
package samples.exception.nullpointer;

public class NullPointer5 {
  public static void main(String[] args) {
    // 具体的な名前を指定して、Person2オブジェクトを作成。
    Person2 p1 = new Person2("Saitou");
    System.out.println(p1.getName().length());
    
    // 名前を指定せず、Person2オブジェクトを作成。
    Person2 p2 = new Person2();
    System.out.println(p2.getName().length());
  }
}

コマンド プロンプト

C:\JavaMaster\bin>java -cp . samples.exception.nullpointer/NullPointer5 
6
0

この例では、2つのPerson2 オブジェクトを作成し、それぞれp1 と p2 という変数に格納しています。 p1 には、適当な名前を設定していますが、p2 には、名前を指定していません。 いずれの場合でも、NullPointerException は発生しないことがわかります。 例外を処理するためのtry〜catch も必要なくなり、プログラムがすっきりしています。