目的
- Javaの等価判定でNullPonterExceptionが発生してしまう場合の、回避方法を学ぼう
対象読者
- Java入門者
- Javaの等価判定をなんとなくでコードを記載している
- 等価判定ってなに?って人
等価判定とは
複数のオブジェクトが同じであればtrue,異なればfalseとなることを言います。
似たような比較に等値判定がありますが、使用方法は若干違います。
等価判定の使用方法
オブジェクトを生成して、実際に等価判定を行ってみました。
// 等価判定の場合
// 型:String
String s1 = "サンプル";
String s2 = "サンプル";
String s3 = "さんぷる";
System.out.println("s1,s2を比較" + s1.equals(s2));
System.out.println("s1,s3を比較" + s1.equals(s3));
true
false
解説
equalsで比較をしていることに注目してみよう。
まず、結果はtrueとfalseが表示されている。
オブジェクトの比較としては、最初はs1とs2で中身が両方サンプル、次の比較がs1とs3で中身が両方同一ではないことが確認できます。
それによって、オブジェクトの中身が同一であれば、true、同一でなければfalseというのが想像できると思います。
等値判定の使用方法
オブジェクトを生成して、実際に等値判定を行ってみました。
// 等値判定の場合
// 型:String
String s1 = "サンプル";
String s2 = "サンプル";
String s3 = s1;
System.out.println("s1,s2を比較" + s1 == s2);
System.out.println("s1,s3を比較" + s1 == s3);
false
true
解説
先ほど(equals)とは違う == で比較をしていることに注目してみよう。
まず、結果はfalseとtrueが表示されている。
オブジェクトの比較としては、最初はs1とs2で中身が両方サンプル、次の比較がs1とs3で中身が同一であることが確認できます。
ただ先ほどとは違い、オブジェクトの中身を比較しているようには見えません。
中身を比較していたら、先ほどの下記のような結果になるのは想定できるはずです。
それによって、オブジェクトの中身が同一であれば、true、同一でなければfalseというのが想像できると思います。
まず比較対象としては、オブジェクトの参照値となります。
オブジェクトの参照値となりますが、詳しくは話さないため、下記などを参考にしてください。
参照値について、理解したら結果がs1とs3がtrueなのは理解できたはずです。
(補足)s1の参照値がs3に入ってるのは、上記コードから読み取れたはずです。
さて、いよいよ等価判定のNullPointerExceptionの回避方法を説明しよう
等価判定〜NullPointerExceptionの回避方法
今回の方法としては、DTOに詰められているデータに対しての等価判定を行う場合となります。
(データベース設計に関しては、無視してください...)
// 名前
private String name;
public String getname(){
return name;
}
public void setname(String name){
this.name = name;
}
// インスタンス生成
private DTO dto;
// 等価判定
// 例えがおかしいですが...(nameに固定値が...
if(dto.getname().equals("山田"){ // ここで異常終了
}else{
if(StringUtils.isEmpty(dto.getname())){
}
}
この製造の仕方だと、テストケースで引っかかるとは思いますが、NullPointerの例外が発生します。
なぜかという比較しようとしているdto.getname() がnullが来た場合、比較できないので例外が発生しますよね...
自分はもちろん経験済みですが
回避策としては、下記があるのかなと思っています。(それ以外思い浮かばず...)
- 固定値がくることがあれば定数を左に持ってくる
- Nullチェックを先に判定する。
- 『Objects.equals()』を使用する
- 『StringUtils.equals()』を使用する。
定数を左
// インスタンス生成
private DTO dto;
// 等価判定
+ // 1の場合
+ final String KEY_WORD = "山田";
+ if(KEY_WORD.equals(dto.getname());
- // 例えがおかしいですが...(nameに固定値が...
- if(dto.getname().equals("山田"){
// 処理記述
}else{
if(StringUtils.isEmpty(dto.getname())){
// 処理記述
}
}
nullチェックを先に行う
// インスタンス生成
private DTO dto;
// 等価判定
+ // 2の場合
+ if(StringUtils.isEmpty(dto.getname())){
// 本来は処理記述
}else{
- // 例えがおかしいですが...(nameに固定値が...
if(dto.getname().equals("山田"){
// 処理記述
}
}
Objects.equalsの使用
// インスタンス生成
private DTO dto;
// 等価判定
+ // 3の場合
- // 例えがおかしいですが...(nameに固定値が...
- if(dto.getname().equals("山田"){
+ if(Objects.equals(dto.getname(),"山田"){
// 処理記述
}
}
StringUtils.equalsの使用
// インスタンス生成
private DTO dto;
// 等価判定
+ // 4の場合
- // 例えがおかしいですが...(nameに固定値が...
- if(dto.getname().equals("山田"){
+ if(StringUtils.equals(dto.getname(),"山田"){
// 処理記述
}
}
番号 | 想定される使用方法 |
---|---|
1 | 予め判定を行う片方が"固定値"であれば、使用できる想定です。 |
2 | 空,nullチェックを先に行う理由は、ぬるぽ回避ぐらいですかね... |
3 | 比較する対象がどちらも"null"要素が入る場合、使用するのが望ましいんですかね。 |
4 | 比較する対象がどちらも"null"要素が入る場合、使用するのが望ましいんですかね。 |
3番と4番の違いがそこまで理解できてなく....
一旦はこんな形で回避できるの中〜って思っています。
最後まで見ていただき、ありがとうございます。
※誤りが合った場合、適宜修正は行っていきます。