web-dev-qa-db-ja.com

Boolean.valueOf()がNullPointerExceptionを生成することがある

私はこのコードを持っています:

package tests;

import Java.util.Hashtable;

public class Tests {

    public static void main(String[] args) {

        Hashtable<String, Boolean> modifiedItems = new Hashtable<String, Boolean>();

        System.out.println("TEST 1");
        System.out.println(modifiedItems.get("item1")); // Prints null
        System.out.println("TEST 2");
        System.out.println(modifiedItems.get("item1") == null); // Prints true
        System.out.println("TEST 3");
        System.out.println(Boolean.valueOf(null)); // Prints false
        System.out.println("TEST 4");
        System.out.println(Boolean.valueOf(modifiedItems.get("item1"))); // Produces NullPointerException
        System.out.println("FINISHED!"); // Never executed
    }
}

私の問題は、なぜテストがうまく機能するのか理解できないことです(falseを出力し、NullPointerExceptionを生成しません)テスト4NullPointerExceptionをスローします。テストでわかるように、12nullmodifiedItems.get("item1")は等しく、nullです。

動作はJava 7と8で同じです。

113
David E

どのオーバーロードが呼び出されているかを注意深く調べる必要があります。

  • Boolean.valueOf(null)が呼び出しています Boolean.valueOf(String) 。これは、nullパラメーターを指定しても、NPEをスローしません。
  • Boolean.valueOf(modifiedItems.get("item1"))は、 Boolean.valueOf(boolean) を呼び出しています。これは、modifiedItemsの値がBoolean型であり、ボックス化解除変換が必要だからです。 modifiedItems.get("item1")nullであるため、NPEをスローするのはBoolean.valueOf(...)ではなく、その値のボックス化解除です。

どのオーバーロードが呼び出されるかを決定するためのルールは pretty hairy ですが、おおよそ次のようになります。

  • 最初のパスでは、ボックス化/ボックス化解除を許可せずにメソッド一致が検索されます(可変アリティメソッドも)。

    • nullStringの許容値ですが、booleanではないため、このパスではBoolean.valueOf(null)Boolean.valueOf(String)と一致します。
    • Booleanは、Boolean.valueOf(String)またはBoolean.valueOf(boolean)のいずれにも受け入れられないため、Boolean.valueOf(modifiedItems.get("item1"))のこのパスで一致するメソッドはありません。
  • 2番目のパスでは、メソッドの一致が検索され、ボクシング/アンボクシングが可能になります(ただし、可変アリティメソッドは許可されません)。

    • Booleanbooleanにアンボックス化できるため、このパスでBoolean.valueOf(boolean)Boolean.valueOf(modifiedItems.get("item1"))に一致します。しかし、それを呼び出すには、コンパイラーがアンボックス化変換を挿入する必要があります:Boolean.valueOf(modifiedItems.get("item1").booleanValue())
  • (変数アリティメソッドを許可する3番目のパスがありますが、最初の2つのパスがこれらのケースに一致したため、ここでは関係ありません)

173
Andy Turner

modifiedItems.getBooleannotStringにキャスト可能)を返すため、署名は使用されるのは Boolean.valueOf(boolean) です。ここで、Booleanはプリミティブbooleanにアウトボックス化されています。 nullがそこに返されると、送信ボックスはNullPointerExceptionで失敗します。

14
Mureinik

メソッド署名

メソッドBoolean.valueOf(...)には2つのシグネチャがあります。

  1. public static Boolean valueOf(boolean b)
  2. public static Boolean valueOf(String s)

modifiedItems値はBooleanです。 BooleanStringにキャストできないため、最初の署名が選択されます

ブール型のアンボクシング

あなたの声明で

Boolean.valueOf(modifiedItems.get("item1"))

として読むことができます

Boolean.valueOf(modifiedItems.get("item1").booleanValue())   

ただし、modifiedItems.get("item1")nullを返すため、基本的には

null.booleanValue()

明らかにNullPointerExceptionにつながります

11
Al-un

Andyが既にNullPointerExceptionの理由を非常によく説明しているように:

これは、ブールのボックス化解除によるものです。

Boolean.valueOf(modifiedItems.get("item1"))

に変換されます:

Boolean.valueOf(modifiedItems.get("item1").booleanValue())

実行時に、modifiedItems.get("item1")がnullの場合、NullPointerExceptionをスローします。

ここで、対応する返されたオブジェクトがnullの場合、それぞれのプリミティブへの次のクラスのボックス化解除によりNullPointerException例外が発生する可能性があるという点をもう1つ追加します。

  1. バイト-バイト
  2. char-キャラクター
  3. float-フロート
  4. int-整数
  5. 長い-長い
  6. ショート-ショート
  7. ダブル-ダブル

コードは次のとおりです。

    Hashtable<String, Boolean> modifiedItems1 = new Hashtable<String, Boolean>();
    System.out.println(Boolean.valueOf(modifiedItems1.get("item1")));//Exception in thread "main" Java.lang.NullPointerException

    Hashtable<String, Byte> modifiedItems2 = new Hashtable<String, Byte>();
    System.out.println(Byte.valueOf(modifiedItems2.get("item1")));//Exception in thread "main" Java.lang.NullPointerException

    Hashtable<String, Character> modifiedItems3 = new Hashtable<String, Character>();
    System.out.println(Character.valueOf(modifiedItems3.get("item1")));//Exception in thread "main" Java.lang.NullPointerException

    Hashtable<String, Float> modifiedItems4 = new Hashtable<String, Float>();
    System.out.println(Float.valueOf(modifiedItems4.get("item1")));//Exception in thread "main" Java.lang.NullPointerException

    Hashtable<String, Integer> modifiedItems5 = new Hashtable<String, Integer>();
    System.out.println(Integer.valueOf(modifiedItems5.get("item1")));//Exception in thread "main" Java.lang.NullPointerException

    Hashtable<String, Long> modifiedItems6 = new Hashtable<String, Long>();
    System.out.println(Long.valueOf(modifiedItems6.get("item1")));//Exception in thread "main" Java.lang.NullPointerException

    Hashtable<String, Short> modifiedItems7 = new Hashtable<String, Short>();
    System.out.println(Short.valueOf(modifiedItems7.get("item1")));//Exception in thread "main" Java.lang.NullPointerException

    Hashtable<String, Double> modifiedItems8 = new Hashtable<String, Double>();
    System.out.println(Double.valueOf(modifiedItems8.get("item1")));//Exception in thread "main" Java.lang.NullPointerException
4
Mohit Tyagi

これを理解する方法は、Boolean.valueOf(null)が呼び出されたとき、Javaがnullを評価するように正確に指示されたときです。

ただし、Boolean.valueOf(modifiedItems.get("item1"))が呼び出されると、JavaはBoolean型のHashTableから値を取得するように指示されますが、代わりに行き止まりを検出するBoolean型は見つかりません(null)ブール値を想定していましたが。 NullPointerException例外がスローされるのは、Javaのこの部分の作成者が、この状況がプログラマーの注意を必要とするプログラムの問題のインスタンスであると判断したためです。 (意図しない何かが起こりました。)

この場合、nullが存在することを意図的に宣言することと、オブジェクトが見つからないオブジェクト(null)への参照が見つからないことをJavaで見つけることとの違いが大きくなります。

この回答のNullPointerExceptionの詳細を参照してください: https://stackoverflow.com/a/25721181/442564