Zusammenfassung
Als ich frei war, nahm ich mir Zeit, um Groovy und Scala auf JVM zu lernen, und stellte fest, dass sie mit Null viel vorsichtiger umgehen als frühere Versionen von Java. In Java 8 bietet optional eine sehr elegante Lösung für die funktionelle Programmiernullverarbeitung. In diesem Artikel wird die langjährige schlechte Handhabung von Null in Java erläutert und dann die Verwendung von optional zur Implementierung von Java-funktionalen Programmen einführen.
Der Null, der uns in diesen Jahren störte
In der Java -Welt gibt es eine Legende: Nur wenn Sie die Ausnahme von Null Zeiger wirklich verstehen, können Sie als qualifizierter Java -Entwickler angesehen werden. In unserer Karriere als Java -Charakter werden wir jeden Tag auf verschiedene Nullverarbeitung stoßen. Wir können jeden Tag wiederholt Codes wie das folgende schreiben:
if (null! = obj1) {if (null! = obje2) {// etwas tun}}Wenn Sie eine kleine Sicht haben, wird Javaer einige hübsche Dinge tun und einen Weg finden, um NULL zu beurteilen:
boolean checknotnull (Objekt obj) {return null == obj? Falsch: wahr; } void do () {if (checknotnull (obj1)) {if (checknotnull (obj2)) {// etwas tun}}}Dann kommt die Frage erneut: Wenn ein Null eine leere Zeichenfolge darstellt, was bedeutet dann ""?
Dann sagt uns das Trägheitsdenken: "" und Null sind beide leere Stringcodes? Ich habe einfach den Nullwert aktualisiert:
boolean checknotblank (Objekt obj) {return null! = obj &&! "". Equals (obj)? wahr: falsch; } void do () {if (checknotblank (obj1)) {if (checknotnull (obj2)) {// etwas tun}}}Wenn Sie Zeit haben, können Sie überprüfen, wie viel Code Sie im aktuellen Projekt oder in Ihrem früheren Code geschrieben haben und was dem obigen Code ähnlich ist.
Ich frage mich, ob Sie ernsthaft über eine Frage nachgedacht haben: Was bedeutet ein Null?
Wenn wir uns erinnern, wie oft haben wir Java.lang.NullPointerexception -Ausnahmen in unserer früheren Grammingkarriere begegnet? NullPointerexception ist eine Ausnahme von RunTimeException Level, die nicht erfasst werden muss. Wenn wir versehentlich damit umgehen, sehen wir häufig verschiedene Ausnahmestapelausgänge, die durch NullPointerexception im Produktionsprotokoll verursacht werden. Und basierend auf diesen Ausnahmestapelinformationen können wir die Ursache des Problems überhaupt nicht finden, da es nicht der Ort ist, an dem die Nullpointerexception geworfen wurde, was das Problem verursachte. Wir müssen tiefer gehen, um herauszufinden, wo dieser Null erzeugt wurde, und die Protokolle können zu diesem Zeitpunkt oft nicht verfolgt werden.
Manchmal ist es noch tragischer, dass die Orte, an denen Nullwerte produziert werden, oft nicht in unserem eigenen Projektcode sind. Dies hat eine peinlichere Tatsache - wenn wir verschiedene Schnittstellen von Drittanbietern von unterschiedlicher Qualität nennen, ist es schwer zu erkennen, ob eine Schnittstelle zufällig einen Null zurückgibt ...
Kehren Sie zum vorherigen kognitiven Problem von NULL zurück. Viele Javaer glauben, dass Null "nichts" oder "Wert gibt es nicht". Nach diesem Trägheitsdenken lautet unsere Codelogik: Sie nennen meine Schnittstelle und geben den entsprechenden "Wert" gemäß den Parametern zurück, die Sie mir geben. Wenn diese Bedingung den entsprechenden "Wert" nicht finden kann, werde ich Ihnen natürlich einen Null geben, dass es kein "Ding" gibt. Schauen wir uns den folgenden Code an, der in einem sehr traditionellen und Standard -Java -Codierungsstil geschrieben ist:
Klasse MyEntity {int id; Zeichenfolge Name; String getName () {return name; }} // MainPublic Class Test {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; }}}Dieser Code ist sehr einfach und die tägliche Geschäftsordnung ist definitiv viel komplizierter als diese, aber tatsächlich wird eine große Anzahl unserer Java -Codes nach dieser Routine geschrieben. Menschen, die wissen, wie man Waren benutzt, können auf einen Blick sehen, dass sie am Ende definitiv eine Nullpointerexception werfen werden. Wenn wir jedoch die Geschäftsordnung schreiben, denken wir selten daran, mit diesem möglichen Null umzugehen (möglicherweise wurde das API -Dokument sehr deutlich geschrieben und wird in einigen Fällen null zurückkehren, aber stellen Sie sicher, dass Sie das API -Dokument vor dem Schreiben des Codes sorgfältig lesen.
// MainPublic Class Test {public static void main (String [] args) endgültig myEntity myEntity = getMyEntity (falsch); if (null! = MyEntity) {System.out.println (myEntity.getName ()); } else {System.out.println ("error"); }}}Überlegen Sie sorgfältig über die letzten Jahre, haben wir das alle getan? Wenn einige Nullprobleme erst in der Testphase entdeckt werden können, dann ist das Problem jetzt - wie viele Nulls werden in diesen komplexen und gut strukturierten Geschäftscodes nicht ordnungsgemäß verarbeitet?
Die Reife und Strenge eines Projekts kann oft im Umgang mit Null gesehen werden. Zum Beispiel gab Guava vor JDK1.6 eine elegante Nullverarbeitungsmethode, die zeigt, wie tief die Fähigkeiten sind.
Geistere Nulls verhindern uns am Fortschritt
Wenn Sie ein Javaer sind, der sich auf traditionelle objektorientierte Entwicklung konzentriert, können Sie die verschiedenen durch Null verursachten Probleme gewöhnt. Aber vor vielen Jahren sagte der große Gott, dass Null eine Grube ist.
Tony Hall (weißt du nicht, wer dieser Typ ist? Überprüfen Sie es selbst) einmal gesagt: "Ich nenne es meinen Milliarden-Dollar-Fehler. Es war die Erfindung der Null-Referenz im Jahr 1965. Ich konnte der Versuchung nicht widerstehen, eine Nullreferenz zu setzen, einfach weil es so einfach war, implementiert zu werden." (Die allgemeine Bedeutung lautet: "Ich nenne es die Erfindung von Null als einen unbezahlbaren Fehler. Denn in der Wildnis von Computern im Jahr 1965 waren leere Referenzen zu einfach zu implementieren, sodass ich der Versuchung nicht widerstehen konnte, den Nullzeiger zu erfinden.")
Lassen Sie uns dann sehen, welche anderen Probleme Null einführen werden.
Schauen Sie sich den folgenden Code an:
String address = Person.getCountry (). GetProvince (). GetCity ();
Wenn Sie einige funktionale Sprachen (Haskell, Erlang, Clojure, Scala usw.) gespielt haben, ist das oben genannte eine sehr natürliche Art des Schreibens. Natürlich kann die obige Schreibmethode mit Java implementiert werden.
Um jedoch alle möglichen NULL -Ausnahmen perfekt zu bewältigen, müssen wir dieses elegante Funktionsprogrammierungsparadigma auf diese Weise ändern:
if (Person! = null) {Country Country = Person.getCountry (); if (Country! = null) {Provinz Provinz = Country.getProvince (); if (provinz! = null) {address = provinz.getCity (); }}}In einem Moment kehrte die hochwertige funktionelle Programmierung Java8 vor 10 Jahren zurück. Solche verschachtelten Urteile sind immer noch trivial, erhöhen die Menge an Code und sind unelegant. Wahrscheinlicher ist, dass die Menschen die meiste Zeit vergessen, den Null zu beurteilen, der auftreten kann, selbst ältere Menschen, die seit vielen Jahren Code geschrieben haben, sind keine Ausnahme.
Der obige Abschnitt der Nullverarbeitung, der Schicht für Schicht ist, ist auch ein Teil des traditionellen Java, der lange Zeit kritisiert wird. Wenn Sie frühe Java-Versionen als Ihre Aufklärungssprache verwenden, wirkt sich dieser Geruch von GET-> Wenn NULL-> RETORN Sie über eine lange Zeit beeinflusst (denken Sie in einer ausländischen Gemeinschaft, die genannt wird: Entitätsorientierte Entwicklung).
Verwenden optional zur Implementierung der JAVA -funktionalen Programmierung
Okay, nachdem wir über alle möglichen Probleme gesprochen haben, können wir in eine neue Ära eintreten.
Lange vor dem Start der Java SE 8 -Version hatten andere ähnliche funktionale Entwicklungssprachen ihre eigenen verschiedenen Lösungen. Hier ist Groovys Code:
String Version = computer? .GetSoundCard () ?. GetUSB ()?.
Haskell verwendet eine möglicherweise Typ -Klassenkennung, um Nullwerte zu verarbeiten. Scala, bekannt als Multi-Paradigm-Entwicklungssprache, bietet eine Option [t], die dem Nullverpackung und der Verarbeitung von Null ähnelt.
Java8 führt Java.util.Optional <t> vor, um das Nullproblem der funktionalen Programmierung zu behandeln. Die Verarbeitungsideen von optionalem <t> ähneln denen von Haskell und Scala, aber es gibt einige Unterschiede. Schauen wir uns das folgende Beispiel des Java -Code an:
public class test {public static void main (String [] args) {final String text = "häuso world!"; Optional.ofnullable (Text) // Zeigen Sie an, um eine optionale Shell.MAP (test :: print) zu erstellen. Optional.ofnullable (text) .map (s -> {system.out.println (s); return substring (6);}) .Map (S -> null) // null .ifpresent (System.out :: println) zurückgeben; } // Die Zeichenfolge nach Str [5] private statische String Print (String Str) {System.out.println (str) ausdrucken und abfangen; return Str.substring (6); }} // Consol Output // Num1: Hallo Welt! // Num2: Welt! // num3: // num4: hallo world!(Sie können den obigen Code in Ihre IDE kopieren, vorausgesetzt, JDK8 muss installiert werden.)
Zwei Optionen werden im obigen Code erstellt, und die implementierten Funktionen sind im Grunde genommen gleich. Beide verwenden optional als String -Shell, um die Zeichenfolge abzuschneiden. Wenn während der Verarbeitung ein Nullwert auftritt, wird die Verarbeitung nicht mehr fortgesetzt. Wir können feststellen, dass nach S-> NULL in der zweiten optionalen Erscheinung der anschließenden wenn auch nicht mehr ausgeführt wird.
Achten Sie auf die Ausgabe // Num3:, was bedeutet, dass ein "" "Zeichenausgabe und kein Null.
Optional bietet reichhaltige Schnittstellen für verschiedene Situationen, z. B. das Ändern des Codes an:
public class test {public static void main (String [] args) {final String text = "häuso world!"; System.out.println (Kleinbuchstaben (Text)); // Methode ein Kleinbuchstaben (null, system.out :: println); // Methode zwei} private statische String -Kleinbuchstaben (String Str) {return optional.ofnulable (str) .Map (S -> S. Tolowercase (). Map (S- } private statische Hohlraum -Kleinbuchstaben (String Str, Consumer <String> Verbraucher) {Consumer.accept (Kleinbuchstaben (STR)); }} // output // Hallo Java! // nanAuf diese Weise können wir eine Zeichenfolge dynamisch verarbeiten. Wenn sich der Wert jederzeit als Null befindet, verwenden wir Orelse, um die voreingestellte Standard -NAN -NAN -Stelle zurückzugeben.
Im Allgemeinen können wir jede Datenstruktur optional einwickeln und sie dann auf funktionale Weise verarbeiten, ohne sich um Nulls umzusetzen, die zu jeder Zeit auftreten können.
Schauen wir uns an, wie Person.getCountry ().
Die erste Methode besteht darin, die vorherige Entität nicht zu ändern:
importieren java.util.optional; public class test {public static void main (String [] args) {system.out.println (optional.ofnullable (new Person ()) .map (x-> x.country) .map (x-> x.Provinec) .Map (x-> x.city) .map (x- .orelse ("unkonnwn"); }} Klasse Person {Country Country;} Klasse Country {Provinz Provisionec;} Klasse Provinz {City City;} Klasse City {String Name;}Hier wird optional verwendet, da die Shell jedes Mal zurückgegeben wird. Wenn eine bestimmte Position NULL zurückgibt, erhalten Sie "Unkonwn".
Die zweite Methode besteht darin, alle Werte in optional zu definieren:
Importieren Sie java.util.optional; public class test {public static void main (String [] args) {System.out.println (new Person () .country.flatmap (x -> x.provinec) .flatMap (Provinz: GetCity) .FlatMap (x -> x.Name) .Onelse ("). }} Klasse Person {optional <Country> Country = optional.Empty ();} Klasse Country {optional <provinz> ProvisionC;} Klasse Provinz {optional <stadt> Stadt; Optional <City> getCity () {// für :: return city; }} Klasse City {optional <string> Name;}Die erste Methode kann reibungslos in vorhandene JavaBeans, Entity oder Poja ohne Änderungen integriert werden und kann leichter in Schnittstellen von Drittanbietern (z. B. Frühlingsbohnen) integriert werden. Es wird empfohlen, dass die erste optionale Methode als Hauptmethode verwendet wird. Schließlich kann nicht jeder im Team den Zweck jedes Get/Set mit einem optionalen verstehen.
Optional liefert auch eine Filtermethode zum Filterdaten (tatsächlich liefern die Schnittstellen im Stream-Stil in Java 8 Filtermethoden). Zum Beispiel haben wir in der Vergangenheit beurteilt, dass der Wert existierte und entsprechende Verarbeitung erstellt hat:
if (provinz! = null) {City City = provinz.getCity (); if (null!Jetzt können wir es ändern
Optional.ofnullable (Provinz) .MAP (x-> x.City) .Filter (x-> "Guangzhou" .Equals (x.getName ()) .MAP (x-> x.Name) .Orelse ("unkonkonw");Zu diesem Zeitpunkt wird die Einführung der funktionalen Programmierung mithilfe optional abgeschlossen. Zusätzlich zu den oben genannten Methoden bietet optional auch Methoden, die auf mehr Anforderungen basieren, Orelseget, Orelsethrow usw. Orelseget stellt aufgrund des Nullwerts eine Nullzeigerausnahme aus, und Orelsethrow wirft eine benutzerdefinierte Ausnahme aus, wenn Null auftritt. Sie können die API -Dokumentation anzeigen, um mehr über alle Methoden zu erfahren.
Am Ende geschrieben
Optional ist nur die Spitze des Eisbergs der Java -funktionellen Programmierung. Es ist notwendig, Merkmale wie Lambda, Stream und FunctionInterface zu kombinieren, um die Wirksamkeit der funktionellen Java8 -Programmierung wirklich zu verstehen. Ich wollte ursprünglich einige optionale Quellcode und Betriebsprinzipien einführen, aber optional selbst hat nur sehr wenig Code und nicht viel API -Schnittstelle. Wenn Sie sorgfältig darüber nachdenken, gibt es nichts zu sagen und Sie werden es weglassen.
Obwohl optional elegant ist, habe ich persönlich das Gefühl, dass es einige Effizienzprobleme gibt, aber es wurde noch nicht überprüft. Wenn jemand Daten hat, lassen Sie es mich bitte wissen.
Ich bin kein "funktionaler Programmieranhänger". Aus der Sicht der Teammanager wird für jede kleine Lernschwierigkeit die Kosten für die Nutzung der Personal und die Teaminteraktion höher sein. Genau wie in der Legende kann LiSP dreißig Mal weniger Code als C ++ haben und ist effizienter in der Entwicklung. Wenn ein inländisches konventionelles IT -Unternehmen LISP wirklich verwendet, um Projekte zu machen, wohin und wie viel kostet es, diese Jungs zu bekommen, die Lisp verwenden?
Aber ich ermutige alle sehr, die Ideen der funktionalen Programmierung zu lernen und zu verstehen. Insbesondere Entwickler, die früher von Java eingedrungen wurden und immer noch nicht wissen, welche Veränderungen Java8 bringen wird, ist Java8 eine gute Gelegenheit. Es wird auch aufgefordert, neue Java8 -Funktionen in das aktuelle Projekt einzuführen. Ein Team, das lange Zeit zusammenarbeitet und eine alte Programmiersprache ständig neue Vitalität injizieren muss. Andernfalls ziehen Sie sich zurück, wenn Sie nicht voranschreiten.
Das obige ist die Sammlung von Java -optionalen Informationen. Wir werden in Zukunft weiterhin relevante Informationen hinzufügen. Vielen Dank für Ihre Unterstützung für diese Website!