[解決済み] なぜJavaでIntegerとintを比較するとNullPointerExceptionが発生するのですか?
質問
この状況を観察して、とても混乱しました。
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つの参照タイプ間の比較は常に参照比較です-
より多くの場合、例えば
Integer
とString
を使用したい場合は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
. 最後に、プログラムがプリミティブ値をボックス化すると、コストがかかり不必要なオブジェクトの作成につながる可能性があります。
ジェネリクスのようにボックス化されたプリミティブを使わざるを得ない場合もありますが、そうでない場合はボックス化されたプリミティブを使うことが正当化されるかどうか真剣に検討すべきです。
参考文献
-
JLS 4.2. プリミティブ型と値
- "この 数値型 は、積分型と浮動小数点型です。
-
JLS 5.1.8 アンボックス変換
- "型は次のように言われます。 数値型に変換可能である である場合、または、アンボクシング変換によって数値型に変換される参照型である場合に、数値型に変換可能であると言われます。
-
アンボックス変換は、[...]を型から変換します。
Integer
型からint
" と入力します。 -
は
r
を投げるので、アンボクシング変換はnull
"
- Java言語ガイド/オートボックス
-
JLS 15.21.1 数値的等式演算子
NullPointerException
と==
-
JLS 15.21.3 参照 等式演算子
!=
と==
- JLS 5.6.2 二進数プロモーション
関連する質問
関連する質問
関連
-
[解決済み] Java enumのメンバーを比較する:==またはequals()?
-
ジャバアレイ
-
[解決済み] JavaでNullPointerExceptionを回避する方法
-
[解決済み] Javaでメモリーリークを発生させるにはどうしたらいいですか?
-
[解決済み] JavaでStringをintに変換するにはどうしたらいいですか?
-
[解決済み] Mavenを使用して、依存関係を持つ実行可能なJARを作成するにはどうすればよいですか?
-
[解決済み] なぜJavaにはtransientフィールドがあるのですか?
-
[解決済み] 特定のUnicode文字を含むコメントでのJavaコードの実行が許可されているのはなぜですか?
-
[解決済み] 整数の左側にゼロを埋め込むにはどうしたらいいですか?
-
[解決済み】JSP 2を使用して、JSPファイル内のJavaコードを回避するにはどうすればよいですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
mvn' は、内部または外部のコマンド、操作可能なプログラムまたはバッチファイルとして認識されません。
-
無効なメソッド宣言
-
ジャバアレイ
-
アノテーション「@Retention」の役割
-
Web Project JavaでPropertiesファイルを読み込むと、「指定されたファイルがシステムで見つかりません」というソリューションが表示されます。
-
Java JDKのダイナミックプロキシ(AOP)の使用と実装の原理分析
-
CAS 5.1.8でhttpをサポートし、認証されていない認可サービスエラーのプロンプトが表示される問題を解決した。
-
[解決済み] String.equals対== [重複] です。
-
[解決済み】JavaとC#のintとIntegerの違いは何ですか?
-
[解決済み] Boolean.valueOf()でNullPointerExceptionが発生することがある。