134 votes

Pourquoi l'instruction String Switch ne prend-elle pas en charge la casse NULL?

Je me demande simplement pourquoi l’instruction Java 7 switch ne prend pas en charge les cas null et renvoie à la place NullPointerException ? Voir la ligne commentée ci-dessous (exemple tiré de l'article des tutoriels Java sur switch ):

 {
    String month = null;
    switch (month) {
        case "january":
            monthNumber = 1;
            break;
        case "february":
            monthNumber = 2;
            break;
        case "march":
            monthNumber = 3;
            break;
        //case null:
        default: 
            monthNumber = 0;
            break;
    }

    return monthNumber;
}
 

Cela aurait évité une condition if pour le contrôle nul avant chaque utilisation de switch .

150voto

Paul Bellora Points 26524

Comme damryfbfnetsi remarquer dans les commentaires, JLS §14.11 a la note suivante:

L'interdiction d'utiliser, null comme un interrupteur étiquette empêche d'écrire du code qui ne peut jamais être exécutée. Si l' switch expression est d'un type de référence, qui est, String ou d'une boîte de type primitif ou d'un type d'énumération, alors une erreur d'exécution se produit si l'expression est évaluée à null au moment de l'exécution. Dans le jugement des concepteurs du langage de programmation Java, c'est un meilleur résultat que silencieusement le saut de l'ensemble de l' switch déclaration ou de choisir d'exécuter les instructions (le cas échéant) après l' default de l'étiquette (le cas échéant).

(l'emphase est mienne)

Alors que la dernière phrase saute au-dessus de la possibilité d'utiliser case null:, il semble raisonnable et offre une vue sur la langue des designers intentions.

Si nous plutôt un regard sur les détails de mise en œuvre, ce blog de Christian Hujer a quelques perspicace les spéculations sur les raisons null n'est pas autorisé dans les commutateurs (bien qu'il se concentre sur enum commutateurs plutôt que pour l' Strings):

Sous le capot, l' switch déclaration généralement les compiler en un tablesswitch de byte code. Et le "physique" argument switch ainsi que ses affaires sont ints. L'int de la valeur de l'interrupteur est déterminé par l'invocation de la méthode de Enum.ordinal(). [...] Les ordinaux commencer à zéro.

Cela signifie que, cartographie, null de 0 ne serait pas une bonne idée. Un interrupteur sur la première valeur d'énumération serait indistinguishible de null. Peut-être que ça aurait été une bonne idée de commencer à compter les ordinaux pour les enums à 1. Cependant, il n'a pas été définie comme ça, et cette définition ne peut pas être changé.

Alors qu' String commutateurs sont mis en œuvre différemment, l' enum interrupteur est venu en premier et créé un précédent pour comment le fait de passer sur un type de référence doit se comporter lorsque la référence est - null.

35voto

bayou.io Points 3680

En général, null est méchant à gérer; peut-être qu'une meilleure langue peut vivre sans null .

Votre problème pourrait être résolu par

     switch(month==null?"":month)
    {
        ...
        //case "":
        default: 
            monthNumber = 0;

    }
 

15voto

Prashant Bhate Points 4669

C'est une tentative de réponse pourquoi il jette NullPointerException

Sortie de javap de commande ci-dessous révèle que case est choisi en fonction sur le hashcode de la switch chaîne de l'argument et donc jette NPE lorsqu' .hashCode() est invoquée sur une chaîne vide.

6: invokevirtual #18                 // Method java/lang/String.hashCode:()I
9: lookupswitch  { // 3
    -1826660246: 44
     -263893086: 56
      103666243: 68
        default: 95
   }

Cela signifie basé sur les réponses à javas Hashcode peut produire le même hashcode pour différentes chaînes? bien que rare, il est encore possible de deux cas appariés (deux chaînes avec le même code de hachage) Voir cette ex ci-dessous

    int monthNumber;
    String month = args[0];

    switch (month) {
    case "Ea":
        monthNumber = 1;
        break;
    case "FB":
        monthNumber = 2;
        break;
    // case null:
    default:
        monthNumber = 0;
        break;
    }
    System.out.println(monthNumber);

javap pour qui

  10: lookupswitch  { // 1
              2236: 28
           default: 59
      }
  28: aload_3       
  29: ldc           #22                 // String Ea
  31: invokevirtual #24                 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
  34: ifne          49
  37: aload_3       
  38: ldc           #28                 // String FB
  40: invokevirtual #24                 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
  43: ifne          54
  46: goto          59 //Default

eh bien comme vous pouvez le voir, une seule affaire est généré, mais avec deux si la condition à vérifier mach avec chaque cas de la chaîne. Très intéressant et compliqué la mise en oeuvre de cette fonctionnalité !

1voto

BlackHatSamurai Points 6211

Selon Java Docs:

Un commutateur fonctionne avec les types de données primitives byte, short, char et int. Il fonctionne également avec les types énumérés (décrits dans Types énumérés), la classe String et quelques classes spéciales qui encapsulent certains types primitifs: Caractère, Octet, Court et Entier (traité dans Nombres et chaînes).

Puisque null n’a pas de type et n’est une instance de rien, cela ne fonctionnera pas avec une instruction switch.

0voto

amrith Points 652

La réponse est simplement que si vous utilisez un commutateur avec un type de référence (tel qu'un type primitif en boîte), l'erreur d'exécution se produira si l'expression est nulle, car unboxing jetterait le NPE.

donc case null (ce qui est illégal) ne pourra jamais être exécuté de toute façon;)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X