résumé
Quand j'étais libre, je prenais le temps d'apprendre Groovy et Scala en cours d'exécution sur JVM, et j'ai découvert qu'ils génèrent Null beaucoup plus prudemment que les versions précédentes de Java. Dans Java 8, Facultatif donne une solution très élégante pour la programmation fonctionnelle du traitement nul. Cet article expliquera la mauvaise gestion de longue date de Null en Java, puis présentera l'utilisation de la programmation fonctionnelle Java en option.
Le nul qui nous a dérangés au cours de ces années
Il y a une légende dans le monde Java: ce n'est que lorsque vous comprenez vraiment l'exception du pointeur nul que vous pouvez être considéré comme un développeur Java qualifié. Dans notre carrière de personnage Java, nous rencontrerons divers traitements nuls chaque jour. Nous pouvons écrire des codes comme les suivants à plusieurs reprises tous les jours:
if (null! = obj1) {if (null! = obje2) {// faire quelque chose}}Si vous avez un peu de vision, Javaer fera de jolies choses et trouvera un moyen de juger null:
booléen checknotnull (objet obj) {return null == obj? false: vrai; } void do () {if (checknotnull (obj1)) {if (checknotnull (obj2)) {// faire quelque chose}}}Ensuite, la question revient: si un NULL représente une chaîne vide, que signifie ""?
Ensuite, la pensée inertielle nous dit: "" Et null sont tous deux des codes de chaîne vides? J'ai simplement mis à niveau la valeur nul:
booléen checkNotblank (objet obj) {return null! = obj &&! "". equals (obj)? vrai: false; } void do () {if (checkNotblank (obj1)) {if (checknotnull (obj2)) {// faire quelque chose}}}Si vous avez le temps, vous pouvez consulter la quantité de code que vous avez écrit dans le projet actuel ou votre code passé et ce qui est similaire au code ci-dessus.
Je me demande si vous avez sérieusement pensé à une question: que signifie un nul?
Rappelant, combien de fois avons-nous rencontré des exceptions java.lang.nullpointerException dans notre précédente carrière de grammage? NullPointerException est une exception de niveau RuntimeException qui n'a pas besoin d'être capturée. Si nous le gérons accidentellement, nous voyons souvent diverses sorties de pile d'exceptions causées par NullPointerException dans le journal de production. Et sur la base de ces informations de pile d'exception, nous ne pouvons pas localiser la cause du problème, car ce n'est pas l'endroit où la NullPointerException a été lancée, ce qui a provoqué le problème. Nous devons aller plus loin pour savoir où ce null a été généré, et les journaux sont souvent incapables d'être suivis pour le moment.
Parfois, il est encore plus tragique que les endroits où les valeurs nulles sont produites ne sont souvent pas dans notre propre code de projet. Cela a un fait plus embarrassant - lorsque nous appelons diverses interfaces tierces de qualité différente, il est difficile de dire si une interface renvoie un null par hasard ...
Revenez au problème cognitif précédent de Null. Beaucoup de Javaers croient que Null signifie «rien» ou «la valeur n'existe pas». Selon cette pensée inertielle, notre logique de code est: vous appelez mon interface et renvoyez la "valeur" correspondante en fonction des paramètres que vous me donnez. Si cette condition ne peut pas trouver la "valeur" correspondante, alors bien sûr, je vous retournerai un null qu'il n'y a pas de "chose". Jetons un coup d'œil au code suivant, qui est écrit dans un style de codage Java très traditionnel et standard:
classe Myentity {int id; Nom de chaîne; String getName () {Nom de retour; }} // Test de classe MainPublic {public static void main (String [] args) final myentity myentity = getMyentity (false); System.out.println (Myentity.getName ()); } private getMyentity (boolean issuc) {if (issuc) {return new Myentity (); } else {return null; }}}Ce morceau de code est très simple, et le code commercial quotidien est certainement beaucoup plus compliqué que cela, mais en fait, un grand nombre de nos codes Java sont écrits en fonction de cette routine. Les gens qui savent utiliser des marchandises peuvent voir en un coup d'œil qu'ils jetteront certainement une nulpointerException à la fin. Cependant, lorsque nous écrivons du code commercial, nous pensons rarement à traiter avec ce document NULL possible (peut-être que le document API a été écrit très clairement et reviendra NULL dans certains cas, mais vous assurez-vous que vous lirez soigneusement le document API avant de commencer à écrire le code?), Jusqu'à ce que nous atteignions une certaine étape de test, un jugement nullpo-intertexception a soudainement apparu qui pourrait être retourné.
// Test de classe MainPublic {public static void main (String [] args) final myentity myentity = getMyentity (false); if (null! = myentity) {System.out.println (Myentity.getName ()); } else {System.out.println ("erreur"); }}}Pensez attentivement aux dernières années, avons-nous tous fait cela? Si certains problèmes nuls ne peuvent pas être découverts avant la phase de test, alors le problème est maintenant - combien de nuls ne sont pas correctement traités dans ces codes commerciaux complexes et bien structurés?
La maturité et la rigueur d'un projet peuvent souvent être vues lorsqu'ils traitent avec Null. Par exemple, Guava a donné une élégante méthode de traitement nul avant JDK1.6, ce qui montre à quel point les compétences sont profondes.
Nulls fantomatiques nous empêche de progresser
Si vous êtes un Javaer se concentrant sur le développement traditionnel orienté objet, vous pouvez être utilisé aux divers problèmes causés par Null. Mais il y a de nombreuses années, le grand dieu a dit que Null est une fosse.
Tony Hall (ne savez-vous pas qui est ce gars? Allez le vérifier vous-même) a dit: "Je l'appelle mon erreur d'un milliard de dollars. C'était l'invention de la référence nul en 1965. Je n'ai pas pu résister à la tentation de mettre une référence nulle, simplement parce qu'elle était si facile à mettre en œuvre." (Le sens général est: "Je l'appelle l'invention de Null une erreur inestimable. Parce que dans le désert des ordinateurs en 1965, les références vides étaient trop faciles à mettre en œuvre, donc je n'ai pas pu résister à la tentation d'inventer le pointeur nul.").
Ensuite, voyons quels autres problèmes introduiront.
Consultez le code suivant:
String Address = Person.getCountry (). GetProvince (). GetCity ();
Si vous avez joué des langues fonctionnelles (Haskell, Erlang, Clojure, Scala, etc.), ce qui précède est une façon très naturelle d'écrire. Bien sûr, la méthode d'écriture ci-dessus peut être implémentée à l'aide de Java.
Mais afin de gérer parfaitement toutes les exceptions nuls possibles, nous devons changer ce paradigme de programmation de fonction élégante à cela:
if (personne! = null) {country country = personne.getCountry (); if (country! = null) {province province = country.getProvince (); if (province! = null) {adresse = province.getCity (); }}}En un instant, la programmation fonctionnelle de haute qualité Java8 est revenue il y a 10 ans. Ces jugements imbriqués sont toujours triviaux, augmentant la quantité de code et inélégant. Plus susceptibles de se produire: la plupart du temps, les gens oublieront de juger les nuls qui peuvent survenir, même les personnes âgées qui ont écrit du code depuis de nombreuses années ne font pas exception.
La section ci-dessus du traitement nul, qui est imbriqué par couche, fait également partie du Java traditionnel critiqué pendant longtemps. Si vous utilisez les premières versions Java comme langue des Lumières, cette odeur de get-> si null-> retour vous affectera pendant une longue période (rappelez-vous dans une communauté étrangère, qui est appelée: développement orienté vers l'entité).
Utilisation de la programmation fonctionnelle en option pour implémenter Java
D'accord, après avoir parlé de toutes sortes de problèmes, nous pouvons entrer dans une nouvelle ère.
Bien avant le lancement de la version Java SE 8, d'autres langages de développement fonctionnel similaires avaient leurs propres solutions. Voici le code de Groovy:
String version = Computer? .GetSoundCard () ?. getUSB () ?. getVersion (): "unkonwn";
Haskell utilise un identifiant de classe peut-être type pour traiter les valeurs nulles. Scala, connu sous le nom d'un langage de développement multi-paradigme, offre une option [t] qui est similaire à peut-être, pour l'enveloppe et le traitement nul.
Java8 présente java.util.optional <t> pour gérer le problème nul de la programmation fonctionnelle. Les idées de traitement de <T> facultatives sont similaires à celles de Haskell et Scala, mais il existe des différences. Jetons un coup d'œil à l'exemple suivant du code Java:
Test de classe publique {public static void main (String [] args) {final String text = "Hallo World!"; Facultatif.OfNullable (texte) // Afficher pour créer un shell.map facultatif (test :: print) .map (test :: print) .ifpresent (System.out :: println); Facultatif.ofNullable (texte) .map (s -> {System.out.println (s); return s.substring (6);}) .map (s -> null) // return null .ifpresent (System.out :: println); } // Imprime et intercepte la chaîne après Str [5] Private Static String Print (String Str) {System.out.println (str); return str.substring (6); }} // Consol Output // num1: Hallo World! // num2: world! // num3: // num4: Hallo World!(Vous pouvez copier le code ci-dessus dans votre IDE, à condition que JDK8 soit installé.)
Deux options sont créées dans le code ci-dessus, et les fonctions implémentées sont essentiellement les mêmes. Ils utilisent tous deux facultatif comme shell de chaîne pour tronquer la chaîne. Lorsqu'une valeur nulle est rencontrée pendant le traitement, le traitement ne sera plus poursuivi. Nous pouvons constater qu'après que S-> null apparaît dans le deuxième facultatif, l'IFFResent ultérieur ne sera plus exécuté.
Faites attention à la sortie // num3:, ce qui signifie qu'un caractère "" est sorti, pas un null.
Fonctionnel fournit des interfaces riches pour gérer diverses situations, telles que la modification du code pour:
Test de classe publique {public static void main (String [] args) {final String text = "Hallo World!"; System.out.println (minuscules (texte)); // Méthode One Minkecase (null, System.out :: println); // Méthode Two} Private Static String minas (String Str) {return Facultatif.ofNullable (Str) .map (S -> S.TolowerCase ()). Map (S-> S.replace ("World", "java")). Orelse ("nan"); } Private Static Void minase (String Str, Consumer <string> Consumer) {Consumer.Accept (minuscules (STR)); }} // sortie // hallo java! // nanDe cette façon, nous pouvons traiter dynamiquement une chaîne. Si la valeur est nul à tout moment, nous utilisons Orelse pour renvoyer le "nan" par défaut prédéfini.
En général, nous pouvons envelopper n'importe quelle structure de données en option, puis les traiter de manière fonctionnelle sans avoir à se soucier des nuls qui peuvent apparaître à tout moment.
Jetons un coup d'œil à la façon dont Person.getCountry (). GetProvince (). GetCity () mentionné plus tôt ne nécessite pas un tas de sites pour le gérer.
La première méthode consiste à ne pas modifier l'entité précédente:
import java.util.optional; public class test {public static void main (string [] args) {System.out.println (facultatif.ofNullable (new personne ()) .map (x-> x.country) .map (x-> x.provinec) .map (x-> x.city) .map (x-> x.name) .orelse ("unkonwn")); }} classe de classe {country country;} classe Country {province provisionec;} province de classe {City City;} classe City {Nom de la chaîne;}Ici, facultatif est utilisé lorsque le shell est revenu à chaque fois. Si un certain poste renvoie nul, vous obtiendrez "unkonwn".
La deuxième méthode consiste à définir toutes les valeurs en option:
Importer java.util.optional; Test de classe publique {public static void main (String [] args) {System.out.println (new Person () .Country.flatMap (x -> x.provinec) .flatmap (province :: getCity) .flatmap (x -> x.name) .Orelse ("unkonwn"); }} classe de classe {facultatif <country> country = optional.empty ();} classe country {facultatif <provvince> provisionc;} class province {facultatif <ity> city; Facultatif <gity> getCity () {// pour :: return City; }} Class City {Nom <string> facultatif;}La première méthode peut être intégrée en douceur aux javabeans, entités ou POJA existants sans aucun changement, et peut être plus facilement intégré dans des interfaces tierces (telles que les haricots de ressort). Il est recommandé que la première méthode facultative soit utilisée comme méthode principale. Après tout, tout le monde dans l'équipe ne peut pas comprendre le but de chaque GET / SET avec un facultatif.
Facultatif fournit également une méthode de filtre pour le filtrage des données (en fait, les interfaces de style flux dans Java 8 fournissent des méthodes de filtre). Par exemple, dans le passé, nous avons jugé que la valeur existait et a fait un traitement correspondant:
if (province! = null) {City City = province.getCity (); if (null! = City && "guangzhou" .equals (city.getName ()) {System.out.println (City.getName ());} else {System.out.println ("unkonwn");}}Maintenant, nous pouvons le modifier à
Facultatif.ofNullable (province) .map (x-> x.city) .filter (x -> "guangzhou" .equals (x.getName ())) .map (x-> x.name) .orelse ("unkonw");À ce stade, l'introduction de programmation fonctionnelle est terminée en utilisant facultatif. En plus des méthodes mentionnées ci-dessus, Facultatif fournit également des méthodes basées sur plus de besoins, Orelseget, OrelsEthrow, etc. Orelseget lancera une exception de pointeur nul en raison de la valeur nulle, et OrelSethrow lancera une exception définie par l'utilisateur lorsque Null se produit. Vous pouvez afficher la documentation de l'API pour en savoir plus sur toutes les méthodes.
Écrit à la fin
Facultatif n'est que la pointe de l'iceberg de la programmation fonctionnelle Java. Il est nécessaire de combiner des fonctionnalités telles que Lambda, Stream et FunctionInterface pour vraiment comprendre l'efficacité de la programmation fonctionnelle Java8. Je voulais à l'origine introduire un code source et des principes de fonctionnement facultatifs, mais facultatif lui-même a très peu de code et pas beaucoup d'interface d'API. Si vous y réfléchissez attentivement, il n'y a rien à dire et vous l'omettre.
Bien que facultatif soit élégant, je pense personnellement qu'il y a des problèmes d'efficacité, mais il n'a pas encore été vérifié. Si quelqu'un a des données, faites-le moi savoir.
Je ne suis pas un "supporter de programmation fonctionnelle". Du point de vue des chefs d'équipe, car chaque petite difficulté d'apprentissage est augmentée, le coût de l'utilisation du personnel et de l'interaction d'équipe sera plus élevé. Tout comme dans la légende, Lisp peut avoir trente fois moins de code que C ++ et est plus efficace dans le développement, mais si une entreprise informatique conventionnelle nationale utilise vraiment LISP pour faire des projets, où aller et combien coûte ces gars qui utilisent LISP?
Mais j'encourage fortement tout le monde à apprendre et à comprendre les idées de la programmation fonctionnelle. Surtout les développeurs qui avaient été envahis par Java et ne savent toujours pas quels changements Java8 apporteront, Java8 est une bonne opportunité. Il est également encouragé à introduire de nouvelles fonctionnalités Java8 dans le projet actuel. Une équipe qui coopère pendant longtemps et un ancien langage de programmation doivent injecter constamment une nouvelle vitalité, sinon vous battez en retraite si vous ne progressez pas.
Ce qui précède est la collection d'informations facultatives Java. Nous continuerons d'ajouter des informations pertinentes à l'avenir. Merci pour votre soutien pour ce site Web!