La raison a Optional
été ajoutée à Java parce que:
return Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.stream()
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.findFirst()
.getOrThrow(() -> new InternalError(...));
est plus propre que cela:
Method matching =
Arrays.asList(enclosingInfo.getEnclosingClass().getDeclaredMethods())
.stream()
.filter(m -> Objects.equals(m.getName(), enclosingInfo.getName())
.filter(m -> Arrays.equals(m.getParameterTypes(), parameterClasses))
.filter(m -> Objects.equals(m.getReturnType(), returnType))
.getFirst();
if (matching == null)
throw new InternalError("Enclosing method not found");
return matching;
Mon point est qu'Optional a été écrit pour supporter la programmation fonctionnelle , qui a été ajoutée à Java en même temps. (L'exemple est fourni par un blog de Brian Goetz . Un meilleur exemple pourrait utiliser la orElse()
méthode, car ce code lèvera quand même une exception, mais vous obtenez l'image.)
Mais maintenant, les gens utilisent Facultatif pour une raison très différente. Ils l'utilisent pour corriger une faille dans la conception du langage. La faille est la suivante: il n'y a aucun moyen de spécifier quels paramètres et valeurs de retour d'une API sont autorisés à être nuls. Cela peut être mentionné dans les javadocs, mais la plupart des développeurs n'écrivent même pas de javadocs pour leur code, et peu de gens vérifieront les javadocs pendant qu'ils écrivent. Cela conduit donc à beaucoup de code qui vérifie toujours les valeurs nulles avant de les utiliser, même si elles ne peuvent souvent pas être nulles car elles ont déjà été validées à plusieurs reprises neuf ou dix fois dans la pile des appels.
Je pense qu'il y avait une réelle soif de résoudre cette faille, car tant de personnes qui ont vu la nouvelle classe Optional ont supposé que son but était d'ajouter de la clarté aux API. C'est pourquoi les gens posent des questions comme «les getters devraient-ils retourner les options?» Non, ils ne devraient probablement pas, sauf si vous vous attendez à ce que le getter soit utilisé dans la programmation fonctionnelle, ce qui est très peu probable. En fait, si vous regardez où Optional est utilisé dans l'API Java, c'est principalement dans les classes Stream, qui sont au cœur de la programmation fonctionnelle. (Je n'ai pas vérifié très attentivement, mais les classes Stream peuvent être le seul endroit où elles sont utilisées.)
Si vous prévoyez d'utiliser un getter dans un peu de code fonctionnel, il peut être judicieux d'avoir un getter standard et un second qui retourne Facultatif.
Oh, et si vous avez besoin que votre classe soit sérialisable, vous ne devez absolument pas utiliser Facultatif.
Les options sont une très mauvaise solution à la faille de l'API car a) elles sont très verbeuses et b) elles n'ont jamais été conçues pour résoudre ce problème en premier lieu.
Une bien meilleure solution à la faille API est le Nullness Checker . Il s'agit d'un processeur d'annotations qui vous permet de spécifier les paramètres et les valeurs de retour autorisés à être annulés en les annotant avec @Nullable. De cette façon, le compilateur peut analyser le code et déterminer si une valeur qui peut réellement être nulle est passée à une valeur où null n'est pas autorisé. Par défaut, il suppose que rien ne peut être nul à moins qu'il ne soit annoté. De cette façon, vous n'avez pas à vous soucier des valeurs nulles. La transmission d'une valeur nulle à un paramètre entraînera une erreur de compilation. Tester un objet pour null qui ne peut pas être null produit un avertissement du compilateur. Cela a pour effet de faire passer NullPointerException d'une erreur d'exécution à une erreur de compilation.
Cela change tout.
Quant à vos getters, n'utilisez pas facultatif. Et essayez de concevoir vos classes afin qu'aucun des membres ne puisse être nul. Et peut-être essayez d'ajouter le Nullness Checker à votre projet et de déclarer vos getters et setter paramètres @Nullable s'ils en ont besoin. Je ne l'ai fait qu'avec de nouveaux projets. Il génère probablement de nombreux avertissements dans les projets existants écrits avec de nombreux tests superflus pour null, il peut donc être difficile de le mettre à niveau. Mais cela entraînera également de nombreux bugs. J'aime cela. Mon code est beaucoup plus propre et plus fiable à cause de cela.
(Il existe également un nouveau langage qui résout ce problème. Kotlin, qui compile en code octet Java, vous permet de spécifier si un objet peut être nul lorsque vous le déclarez. C'est une approche plus propre.)
Addendum à la publication originale (version 2)
Après y avoir longuement réfléchi, je suis parvenu à contrecœur à la conclusion qu'il est acceptable de retourner Facultatif à une condition: que la valeur récupérée soit en fait nulle. J'ai vu beaucoup de code où les gens retournent régulièrement Facultatif des getters qui ne peuvent pas retourner null. Je vois cela comme une très mauvaise pratique de codage qui ne fait qu'ajouter de la complexité au code, ce qui rend les bogues plus probables. Mais lorsque la valeur renvoyée peut effectivement être nulle, allez-y et encapsulez-la dans un Facultatif.
Gardez à l'esprit que les méthodes conçues pour la programmation fonctionnelle et qui nécessitent une référence de fonction seront (et devraient) être écrites sous deux formes, dont l'une utilise Facultatif. Par exemple, Optional.map()
et les Optional.flatMap()
deux prennent des références de fonction. Le premier prend une référence à un getter ordinaire, et le second en prend un qui renvoie Facultatif. Vous ne rendez donc service à personne en renvoyant un Facultatif où la valeur ne peut pas être nulle.
Cela dit, je vois toujours que l'approche utilisée par le vérificateur de nullité est la meilleure façon de traiter les valeurs nulles, car elles transforment les exceptions NullPointerException des bogues d'exécution pour compiler des erreurs de temps.