28 votes

Conversion de null en int possible ?

Je sais que lorsque je lirai la réponse à cette question, je verrai que j'ai négligé quelque chose qui était sous mes yeux. Mais j'ai passé les 30 dernières minutes à essayer de le découvrir par moi-même sans résultat.

J'écrivais un programme en Java 6 et j'ai découvert une fonctionnalité (pour moi) étrange. Afin d'essayer de l'isoler, j'ai fait deux petits exemples. J'ai d'abord essayé la méthode suivante :

private static int foo()
{
    return null;
}

et le compilateur l'a refusé : Type mismatch : cannot convert from null to int.

Cela me convient et respecte la sémantique Java que je connais. J'ai ensuite essayé ce qui suit :

private static Integer foo(int x)
{
    if (x < 0)
    {
        return null;
    }
    else
    {
        return new Integer(x);
    }
}

private static int bar(int x)
{
    Integer y = foo(x);

    return y == null ? null : y.intValue();
}

private static void runTest()
{
    for (int index = 2; index > -2; index--)
    {
        System.out.println("bar(" + index + ") = " + bar(index));
    }
}

Cela compile sans aucune erreur ! Mais, à mon avis, il devrait y avoir une erreur de conversion de type dans la ligne

    return y == null ? null : y.intValue();

Si j'exécute le programme, j'obtiens le résultat suivant :

bar(2) = 2
bar(1) = 1
bar(0) = 0
Exception in thread "main" java.lang.NullPointerException
    at Test.bar(Test.java:23)
    at Test.runTest(Test.java:30)
    at Test.main(Test.java:36)

Pouvez-vous expliquer ce comportement ?

Mise à jour

Merci beaucoup pour les nombreuses réponses éclairantes. J'étais un peu inquiet car cet exemple ne correspondait pas à mon intuition. Une chose qui me perturbait était qu'un null était converti en un int et je me demandais quel serait le résultat résultat : 0 comme en C++ ? Cela aurait été très étrange. C'est bien que la conversion ne soit pas possible au moment de l'exécution (exception de pointeur nul).

31voto

Jesper Points 65733

Regardons la ligne :

return y == null ? null : y.intValue();

Dans un ? : les deux côtés de la : doivent avoir le même type. Dans ce cas, Java va faire en sorte qu'il ait le type Integer . Un site Integer peut être null donc le côté gauche est correct. L'expression y.intValue() est de type int mais Java va le mettre en boîte automatiquement en tant que Integer (remarque, vous auriez tout aussi bien pu écrire y ce qui vous aurait évité cette autobox).

Maintenant, le résultat doit être déballé à nouveau pour int car le type de retour de la méthode est int . Si vous déballez un Integer c'est-à-dire null vous obtenez un NullPointerException .

Note : Paragraphe 15.25 de la spécification du langage Java explique les règles exactes pour les conversions de type en ce qui concerne le format ? : opérateur conditionnel.

6voto

Kal Points 14230

Le type de retour est ici déduit par Java. C'est là le problème.

http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.25

Voici le problème réel

Si l'un des deuxième et troisième opérandes est de type nul et que le type de l'autre est un type de référence, alors le type de l'expression conditionnelle est ce type de référence.

Donc, fondamentalement, le compilateur déduit que le type de retour de l'expression conditionnelle est Integer et c'est pourquoi il vous permet de compiler avec succès.

EDIT : Voir les règles dans les commentaires

2voto

Dan Tao Points 60518

Cela illustre une différence problématique entre la manière dont un humain lit le code et un compilateur lit le code.

Lorsque vous Si vous voyez une expression ternaire, il est très possible que vous la divisiez mentalement en deux parties, à la manière d'un if / else déclaration :

if (y == null)
    return null;
else
    return y.intValue();

Vous On peut voir que cela n'est pas valable, car il en résulte une branche possible où une méthode définie pour retourner un int renvoie en fait null (illégal !).

Qu'est-ce que le compilateur voit est un expression qui doit avoir un type. Il constate que l'opération ternaire comprend un null d'un côté et un int de l'autre ; en raison du comportement autoboxing de Java, il propose alors une "meilleure estimation" (mon terme, pas celui de Java) du type de l'expression : Integer (ce qui est juste : c'est le seul type qui pourrait légalement être null ou une boîte int ).

Puisque la méthode est censée retourner un int cela ne pose pas de problème du point de vue du compilateur : l'expression renvoyée est évaluée comme étant un Integer qui peuvent être déballées automatiquement.

2voto

irreputable Points 25577

Ceci compile

private static int foo()
{
    return (Integer)null;
}

1voto

Bozho Points 273663

Le problème de l'autounboxing null les valeurs peuvent être vraiment ennuyeuses. Dans votre exemple, il s'agit d'une combinaison de l'inférence du type de résultat de l'opérateur ternaire et de l'autounboxing (il faudrait consulter le JLS pour savoir pourquoi il se comporte ainsi).

Mais d'une manière générale, vous devriez essayer d'éviter d'utiliser des types enveloppants. Utilisez int au lieu de Integer . Si vous avez besoin d'une valeur spéciale signifiant "aucun résultat", alors vous pouvez utiliser Integer.MAX_VALUE par exemple.

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