web-dev-qa-db-fra.com

Boolean.valueOf () produit parfois NullPointerException

J'ai ce code:

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
    }
}

Mon problème est que je ne comprends pas pourquoi Test fonctionne bien (il affiche false et ne produit pas NullPointerException) en attendant Test 4 jette un NullPointerException. Comme vous pouvez le constater dans les tests 1 et 2, null et modifiedItems.get("item1") sont égaux et null.

Le comportement est le même dans Java 7 et 8.

113
David E

Vous devez regarder attentivement quelle surcharge est invoquée:

  • Boolean.valueOf(null) appelle Boolean.valueOf(String) . Cela ne jette pas un NPE même s'il est fourni avec un paramètre null.
  • Boolean.valueOf(modifiedItems.get("item1")) appelle Boolean.valueOf(boolean) , car les valeurs de modifiedItems sont de type Boolean, ce qui nécessite une conversion unboxing. Puisque modifiedItems.get("item1") est null, c'est le décompression de cette valeur - et non la Boolean.valueOf(...) - qui jette le NPE.

Les règles permettant de déterminer quelle surcharge est invoquée sont joli poil , mais elles vont grossièrement comme ceci:

  • Lors d'une première passe, une correspondance de méthode est recherchée sans permettre la boxing/unboxing (ni les méthodes d'arity variable).

    • Parce que null est une valeur acceptable pour un String mais pas boolean, Boolean.valueOf(null) est apparié à Boolean.valueOf(String) dans cette passe;
    • Boolean n'est pas acceptable pour Boolean.valueOf(String) ou Boolean.valueOf(boolean), de sorte qu'aucune méthode ne correspond à cette passe pour Boolean.valueOf(modifiedItems.get("item1")).
  • Dans un second passage, une correspondance de méthode est recherchée, permettant la boxe/désencaissement (mais pas les méthodes d'arité variable).

    • Un Boolean peut être décompressé dans boolean, donc Boolean.valueOf(boolean) correspond à Boolean.valueOf(modifiedItems.get("item1")) dans cette passe; mais le compilateur doit insérer une conversion unboxing pour l'invoquer: Boolean.valueOf(modifiedItems.get("item1").booleanValue())
  • (Un troisième passage autorise les méthodes d'arité variable, mais ce n'est pas pertinent ici, car les deux premiers passages correspondaient à ces cas)

173
Andy Turner

Puisque modifiedItems.get Renvoie un Boolean (qui est non convertible en un String), la signature qui serait utilisé est Boolean.valueOf(boolean) , où Boolean est envoyé à une primitive boolean. Une fois que null y est retourné, la boîte d'envoi échoue avec un NullPointerException.

14
Mureinik

Méthode de signature

La méthode Boolean.valueOf(...) a deux signatures:

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

Votre valeur modifiedItems est Boolean. Vous ne pouvez pas convertir Boolean en String. Par conséquent, la première signature sera choisie.

Unboxing booléen

Dans votre déclaration

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

qui peut être lu comme

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

Cependant, modifiedItems.get("item1") retourne null donc vous aurez essentiellement

null.booleanValue()

ce qui conduit évidemment à un NullPointerException

11
Al-un

Comme Andy a déjà très bien décrit la raison de NullPointerException:

ce qui est dû à la décompression booléenne:

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

se convertir en:

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

au moment de l'exécution, puis il jette NullPointerException si modifiedItems.get("item1") est null.

J'aimerais maintenant ajouter un point supplémentaire: le décompression des classes suivantes de leurs primitives respectives peut également produire une exception NullPointerException si leurs objets renvoyés correspondants sont nuls.

  1. octet - octet
  2. char - Caractère
  3. float - Flotter
  4. int - Entier
  5. long - long
  6. court - court
  7. double double

Voici le code:

    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

Une façon de le comprendre consiste à appeler Boolean.valueOf(null), Java est précisément invité à évaluer null.

Cependant, lorsque Boolean.valueOf(modifiedItems.get("item1")) est appelée, Java indique qu'il faut obtenir une valeur à partir de la table de hachage de type objet Boolean, mais le type n'est pas trouvé. end à la place (null) même si elle s’attendait à une valeur booléenne. L’exception NullPointerException est levée car les créateurs de cette partie de Java ont décidé que cette situation est une instance de quelque chose dans le programme qui nécessite l’aide du programmeur. attention. (Quelque chose d'inattendu est arrivé.)

Dans ce cas, c’est plus la différence entre déclarer délibérément que vous vouliez que le null soit là et Java) trouver une référence manquante à un objet (null) où un objet devait être trouvé.

Voir plus d'informations sur NullPointerException dans cette réponse: https://stackoverflow.com/a/25721181/442564