web-dev-qa-db-fra.com

Le déballage de Null-Object en type primitif entraîne une exception NullPointerException, d'accord?

Cet extrait renvoie un NullPointerException en raison du fait que son unboxed à un type primitif et Long.longValue() est appelé, non?

C'est même facile de voir si vous avez un extrait comme celui-ci:

long value = (Long) null;

Mais le NullPointerException est encore plus difficile à obtenir dans une situation plus complexe comme celle-ci:

long propertyValue = (Long) obj.getProperty(propertyModel.getName());

N'y a-t-il donc aucune possibilité pour le compilateur Java d'en faire une exception plus confortable? Je préférerais un IllegalArgumentException avec un message comme "Vous essayez de convertir un null-Object en un type primitif, cela ne peut pas être fait!"

Cela ne serait-il pas plus approprié? Qu'est-ce que tu penses? Est-ce même possible à l'exécution? Sommes-nous capables de déterminer cette distribution? Je n'ai pas encore regardé le Java bytecode. Peut-être qu'il pourrait être utilisé dans une solution.

On peut répondre à cette question: J'aimerais savoir s'il est possible d'obtenir ce comportement!

39

Selon la spécification du langage Java , le déballage se produit en appelant Number.longValue(), Number.intValue(), etc. Il n'y a pas de magie de code d'octet spéciale, c'est exactement la même chose que si vous appelez ces méthodes manuellement. Ainsi, le NullPointerException est le résultat naturel du déballage d'un null (et en fait mandaté par le JLS).

Lancer une exception différente nécessiterait de vérifier null deux fois lors de chaque conversion de déballage (une fois pour déterminer s'il faut lever l'exception spéciale et une fois implicitement lorsque la méthode est réellement appelée). Je suppose que les concepteurs de langage ne l'ont pas jugé suffisamment utile pour justifier cela.

75

Depuis Java 8 SE, il y a aussi Optional.ofNullable

long value = Optional.ofNullable(obj.getProperty(propertyModel.getName())).orElse(0L)));
15
oluies

C'est une bonne idée d'écrire un petit assistant privé pour des cas comme celui-ci. Ceux-ci peuvent gérer la production de conversions, de messages d'erreur et de valeurs par défaut corrects.

Il est bon de mettre suffisamment "état" de l'opération dans l'exception (dans ce cas, le nom et la valeur de l'option - peut-être même une représentation sous forme de chaîne de la carte des options si elle n'est pas trouvée).

Quelque chose comme:

private long safeGetLong(Map<String, Option> options, String name) {
  if (name == null || options == null)
    throw new IllegalArgumentExcption("You need to give options and name. (name="+name+", opts=" + options));
  Object val = options.get(name);
  if (val == null)
    throw new ConfigurationException("The option name="+name+" is unknown");
  if (val instanceof Long)
    return val.longValue();

  String strVal = null;
  try
  {
    strVal = val.toString();
    return Long.parseValue(strVal);
  } catch (Exception ex) {
    throw new ConfigurationException("Cannot parse " + name + "=" + strVal + " into a Long.");
  }
}

Bien sûr, avoir un objet de configuration qui permet un accès tapé est encore mieux.

Il existe des cadres de validation qui pourraient le faire pour vous, mais je finis généralement par écrire le code moi-même car il correspond mieux aux hiérarchies IN8L et d'exception ou aux conventions de journalisation de l'application en question. Il est difficile de rendre cela générique.

1
eckes

Ce n'est pas ce que IllegalArgumentException signifie. Le compilateur n'a aucune garantie que la valeur sera null jusqu'à l'exécution. Tout ce qu'il sait, c'est le type, qui dans votre exemple est probablement String.

Certainement à l'exécution, lorsque l'exception est levée, le compilateur sait que le problème est une valeur null. Vous pouvez le voir vous-même si vous utilisez un débogueur. Donc, d'un point de vue technologique - et voici la réponse courte à votre question - oui, ce serait possible pour créer un compilateur qui inclura cela dans la description de l'erreur. Mais si vous voulez un message spécial pour les valeurs null, quelle est la prochaine étape? Des messages spéciaux pour les entiers qui sont en dehors de certains limites acceptables par plus de 10? Certes, c'est un peu un exemple stupide, mais j'espère que c'est illustratif.

1
Pops