1. ホーム
  2. java

[解決済み] なぜJavaでIntegerとintを比較するとNullPointerExceptionが発生するのですか?

2023-05-23 02:57:39

質問

この状況を観察して、とても混乱しました。

Integer i = null;
String str = null;

if (i == null) {   //Nothing happens
   ...                  
}
if (str == null) { //Nothing happens

}

if (i == 0) {  //NullPointerException
   ...
}
if (str == "0") { //Nothing happens
   ...
}

ということで、ボクシングの演算が先に実行される(つまり、javaはint値を null からint値を取り出そうとする)、比較演算は優先順位が低いので、例外が投げられたのだと思います。

問題は、なぜJavaでこのように実装されているのか?なぜボクシングは参照の比較よりも優先順位が高いのでしょうか?あるいは、なぜ null に対する検証を実装しなかったのでしょうか?

現時点では、以下のような場合、矛盾しているように見えます。 NullPointerException が投げられ、ラップされたプリミティブでは投げられないというのは矛盾しています。 オブジェクトタイプではスローされません。

どのように解決するのですか?

簡単な答え

重要なポイントはこれです。

  • == 2つの参照タイプ間の比較は常に参照比較です
    • より多くの場合、例えば IntegerString を使用したい場合は equals の代わりに
  • == 参照型と数値プリミティブ型の比較は常に数値比較です。
    • 参照型はアンボクシング変換が行われる
    • アンボックス化 null 常に投げる NullPointerException
  • Javaは String はプリミティブ型ではありません。

上記の記述は、任意の与えられた に対して有効です。 Java コードに適用されます。この理解で、あなたが提示したスニペットには何の矛盾もありません。


長い回答

以下は、JLSの関連セクションです。

JLS 15.21.3 参照 等式演算子 ==!=

等号演算子のオペランドが両方とも参照型または null 型のいずれかである場合、その演算はオブジェクトの等式となります。

これは次のように説明されます。

Integer i = null;
String str = null;

if (i == null) {   // Nothing happens
}
if (str == null) { // Nothing happens
}
if (str == "0") {  // Nothing happens
}

オペランドはどちらも参照型であり、そのため == は参照等価比較です。

これも以下のように説明されています。

System.out.println(new Integer(0) == new Integer(0)); // "false"
System.out.println("X" == "x".toUpperCase()); // "false"

については == を数値の等号にする。 オペランドの少なくとも一方は数値型でなければなりません。 :

JLS 15.21.1 数値的等式演算子 ==!=

等号演算子のオペランドが の両方である場合 であり、数値型であるか で、かつ であり、もう一方は変換可能な である場合、オペランドに対して2進数の数値昇格が行われます。オペランドの昇格型が int または long である場合、整数の等値性テストが実行されます。 float or double` であれば、浮動小数点数の等値性テストが行われます。

バイナリ数値推進は、値集合変換とアンボックス変換を行うことに注意してください。

という説明があります。

Integer i = null;

if (i == 0) {  //NullPointerException
}

以下は Effective Java 第2版 項目49:プリミティブをボックス型プリミティブに優先させる :

まとめると、選択肢があるときはいつでもボックス型プリミティブよりプリミティブを優先して使いましょう。プリミティブ型はよりシンプルで高速です。もしボックス化されたプリミティブを使わなければならないのであれば、注意してください! オートボックスは、ボックス化されたプリミティブを使うことによる冗長性を軽減しますが、危険性を軽減するわけではありません。プログラムが二つのボックス化されたプリミティブを == 演算子で二つの箱型プリミティブを比較するとき、それは同一性比較を行ないますが、それはほとんど確実にあなたが望むことではありません。プログラムがボックス化されたプリミティブとボックス化されていないプリミティブを含む混合型計算をするとき、それはアンボックス化をします。そして、プログラムがアンボックス化をするとき、それは NullPointerException . 最後に、プログラムがプリミティブ値をボックス化すると、コストがかかり不必要なオブジェクトの作成につながる可能性があります。

ジェネリクスのようにボックス化されたプリミティブを使わざるを得ない場合もありますが、そうでない場合はボックス化されたプリミティブを使うことが正当化されるかどうか真剣に検討すべきです。

参考文献

関連する質問

関連する質問