Ich habe auf vielen Websites gelesen. Optional sollte nur als Rückgabetyp verwendet und nicht in Methodenargumenten verwendet werden. Ich kämpfe darum, einen logischen Grund dafür zu finden. Zum Beispiel habe ich eine Logik, die 2 optionale Parameter hat. Daher halte ich es für sinnvoll, meine Methodensignatur wie folgt zu schreiben (Lösung 1):
public int calculateSomething(Optional<String> p1, Optional<BigDecimal> p2 {
// my logic
}
Viele Webseiten geben an, dass Optional nicht als Methodenargumente verwendet werden sollte. In diesem Sinne könnte ich die folgende Methodensignatur verwenden und einen eindeutigen Javadoc-Kommentar hinzufügen, um anzugeben, dass die Argumente null sein können, in der Hoffnung, dass zukünftige Betreuer das Javadoc lesen und daher vor der Verwendung der Argumente immer Nullprüfungen durchführen (Lösung 2). ::
public int calculateSomething(String p1, BigDecimal p2) {
// my logic
}
Alternativ könnte ich meine Methode durch vier öffentliche Methoden ersetzen, um eine schönere Schnittstelle bereitzustellen und klarer zu machen, dass p1 und p2 optional sind (Lösung 3):
public int calculateSomething() {
calculateSomething(null, null);
}
public int calculateSomething(String p1) {
calculateSomething(p1, null);
}
public int calculateSomething(BigDecimal p2) {
calculateSomething(null, p2);
}
public int calculateSomething(String p1, BigDecimal p2) {
// my logic
}
Jetzt versuche ich, den Code der Klasse zu schreiben, die diese Logik für jeden Ansatz aufruft. Optional
Ich rufe zuerst die beiden Eingabeparameter von einem anderen Objekt ab, das s zurückgibt, und rufe dann auf calculateSomething
. Wenn also Lösung 1 verwendet wird, würde der aufrufende Code folgendermaßen aussehen:
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1, p2);
Wenn Lösung 2 verwendet wird, sieht der aufrufende Code folgendermaßen aus:
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));
Wenn Lösung 3 angewendet wird, könnte ich den obigen Code verwenden oder den folgenden (aber es ist deutlich mehr Code):
Optional<String> p1 = otherObject.getP1();
Optional<BigInteger> p2 = otherObject.getP2();
int result;
if (p1.isPresent()) {
if (p2.isPresent()) {
result = myObject.calculateSomething(p1, p2);
} else {
result = myObject.calculateSomething(p1);
}
} else {
if (p2.isPresent()) {
result = myObject.calculateSomething(p2);
} else {
result = myObject.calculateSomething();
}
}
Meine Frage lautet also: Warum wird es als schlechte Praxis angesehen, Optional
s als Methodenargumente zu verwenden (siehe Lösung 1)? Es scheint mir die am besten lesbare Lösung zu sein und macht deutlich, dass die Parameter für zukünftige Betreuer leer / null sein können. (Ich bin mir bewusst, dass die Designer Optional
beabsichtigt haben, es nur als Rückgabetyp zu verwenden, aber ich kann keine logischen Gründe finden, es in diesem Szenario nicht zu verwenden.)
null
?Antworten:
Oh, diese Codierungsstile sind mit etwas Salz zu nehmen.
Im Allgemeinen: Optional werden zwei Zustände vereinheitlicht, die entwirrt werden müssen. Daher besser geeignet für das Ergebnis als für die Eingabe, für die Komplexität des Datenflusses.
quelle
Optional
repräsentiert Parameter einen von drei Zuständen: einemnull
Optional, eine nicht-nullOptional
mitisPresent() == false
und einem nicht-nullOptional
einen Istwert Einwickeln.@NotNull Optional
.Optional
überhaupt verwenden, Status 1 (null
optional) normalerweise einen Programmierfehler anzeigt, so dass Sie es genauso gut nicht behandeln können (lassen Sie es einfach einNullPointerException
)Der beste Beitrag, den ich zu diesem Thema gesehen habe, wurde von Daniel Olszewski geschrieben :
quelle
null
oder bevorzugenOptional
.Es gibt fast keine guten Gründe, nicht
Optional
als Parameter zu verwenden. Die Argumente dagegen beruhen auf Argumenten der Autorität (siehe Brian Goetz - sein Argument ist, dass wir keine Nicht-Null-Optionen erzwingen können) oder dass dieOptional
Argumente null sein können (im Wesentlichen dasselbe Argument). Natürlich kann jede Referenz in Java null sein. Wir müssen dazu ermutigen, dass Regeln vom Compiler erzwungen werden, nicht vom Programmierspeicher (was problematisch ist und nicht skaliert).Funktionale Programmiersprachen fördern
Optional
Parameter. Eine der besten Möglichkeiten, dies zu verwenden, besteht darin, mehrere optionale ParameterliftM2
zu verwenden und eine Funktion zu verwenden, sofern die Parameter nicht leer sind, und eine optionale zurückzugeben (siehe http://www.functionaljava.org/javadoc/4.4/functionaljava/fj/). data / Option.html # liftM2-fj.F- ). Java 8 hat leider eine sehr begrenzte Bibliothek implementiert, die optional unterstützt.Als Java-Programmierer sollten wir nur null verwenden, um mit älteren Bibliotheken zu interagieren.
quelle
@Nonnull
und@Nullable
von javax.annotation? Ich benutze sie ausgiebig in einer Bibliothek, die ich entwickle, und die Unterstützung durch die IDE (IntelliJ) ist sehr gut.@NonNull
völlig in Ordnung ist, wenn sie auf unterschiedliche Weise demselben Zweck dienen?" Für mich gibt es nur ein Argument, das zumindest einen Sinn ergibt: "Optional sollte verwendet werden, um bessere APIs mit einem eindeutigen Rückgabetyp bereitzustellen. Für Methodenargumente können jedoch überladene Funktionen verwendet werden." - Dennoch denke ich nicht, dass dies ein Argument ist, das stark genug ist.Dieser Rat ist eine Variante der Faustregel "Seien Sie in Bezug auf Eingaben so unspezifisch wie möglich und in Bezug auf Ausgaben so spezifisch wie möglich".
Wenn Sie eine Methode haben, die einen einfachen Wert ungleich Null annimmt, können Sie diesen normalerweise über den Wert zuordnen
Optional
, sodass die einfache Version in Bezug auf Eingaben streng unspezifischer ist. Es gibt jedoch eine Reihe möglicher Gründe, warum SieOptional
dennoch ein Argument benötigen möchten :Optional
Optional
wenn der angegebene Wert leer istSie findenOptional
es so großartig, dass jeder, der Ihre API verwendet, dazu aufgefordert werden sollte, etwas darüber zu lernen ;-)quelle
Das Muster mit
Optional
ist für einen, um eine Rückkehr zu vermeidennull
. Es ist immer noch durchaus möglich,null
auf eine Methode überzugehen.Obwohl diese noch nicht wirklich offiziell sind, können Sie Anmerkungen im JSR-308-Stil verwenden, um anzugeben, ob Sie
null
Werte in die Funktion akzeptieren oder nicht . Beachten Sie, dass Sie über das richtige Tool verfügen müssen, um es tatsächlich zu identifizieren, und dass es eher eine statische Überprüfung als eine durchsetzbare Laufzeitrichtlinie bietet, aber es würde helfen.quelle
Optional
das Problem wird auch nicht behoben , daher mein Vorschlag für die Anmerkungen.Das scheint mir ein bisschen albern, aber der einzige Grund, an den ich denken kann, ist, dass Objektargumente in Methodenparametern bereits in gewisser Weise optional sind - sie können null sein. Daher ist es sinnlos, jemanden zu zwingen, ein vorhandenes Objekt zu nehmen und es in ein optionales Objekt zu verpacken.
Abgesehen davon ist es eine vernünftige Sache, Methoden miteinander zu verketten, die Optionen annehmen / zurückgeben, z. B. vielleicht Monade.
quelle
Optional
ist völlig sinnlos?Überprüfen Sie das JavaDoc in JDK10, https://docs.oracle.com/javase/10/docs/api/java/util/Optional.html . Ein API-Hinweis wird hinzugefügt:
quelle
Meiner Meinung nach sollte Optional eine Monade sein, und diese sind in Java nicht denkbar.
In der funktionalen Programmierung beschäftigen Sie sich mit reinen Funktionen höherer Ordnung, die ihre Argumente nur basierend auf ihrem "Geschäftsdomänentyp" annehmen und zusammensetzen. Das Erstellen von Funktionen, die sich auf die reale Welt stützen oder deren Berechnung gemeldet werden sollte (sogenannte Nebenwirkungen), erfordert die Anwendung von Funktionen, die dafür sorgen, dass die Werte automatisch aus den Monaden entpackt werden, die die Außenwelt darstellen (Status, Konfiguration, Futures, vielleicht, entweder, Schriftsteller, etc ...); Dies nennt man Heben. Sie können sich das als eine Art Trennung von Bedenken vorstellen.
Das Mischen dieser beiden Abstraktionsebenen erleichtert die Lesbarkeit nicht, daher sollten Sie sie besser vermeiden.
quelle
Ein weiterer Grund, beim Übergeben eines
Optional
as-Parameters vorsichtig zu sein, besteht darin, dass eine Methode eine SacheOptional
ausführen sollte ... Wenn Sie einen Parameter übergeben, können Sie mehr als eine Sache bevorzugen, es könnte ähnlich sein, einen booleschen Parameter zu übergeben.quelle
if(param.isPresent())
ist dies nicht der beste Ansatz, um Optional zu verwenden. Stattdessen können Sieparam.forEach(() -> {...})
Das Akzeptieren von Optional als Parameter führt zu unnötigem Umbruch auf Anruferebene.
Zum Beispiel im Fall von:
Angenommen, Sie haben zwei Nicht-Null-Zeichenfolgen (dh von einer anderen Methode zurückgegeben):
Sie müssen sie in Optional einwickeln, auch wenn Sie wissen, dass sie nicht leer sind.
Dies wird noch schlimmer, wenn Sie mit anderen "abbildbaren" Strukturen komponieren müssen, d. H. Eithers :
ref:
ref. https://github.com/teamdigitale/digital-citizenship-functions/pull/148#discussion_r170862749
quelle
Ich denke, das liegt daran, dass Sie normalerweise Ihre Funktionen schreiben, um Daten zu manipulieren, und sie dann auf die
Optional
Verwendungmap
und ähnlicher Funktionen heben . Dies fügt das Standardverhalten hinzuOptional
. Natürlich kann es Fälle geben, in denen es notwendig ist, eine eigene Hilfsfunktion zu schreiben, die funktioniertOptional
.quelle
Ich glaube, die Resonanz des Seins besteht darin, dass Sie zuerst prüfen müssen, ob Optional selbst null ist oder nicht, und dann versuchen müssen, den Wert zu bewerten, den es umschließt. Zu viele unnötige Validierungen.
quelle
Optionals sind nicht für diesen Zweck konzipiert, wie Brian Goetz ausführlich erklärt hat .
Sie können jederzeit @Nullable verwenden , um anzugeben , dass ein Methodenargument null sein kann. Wenn Sie eine Option verwenden, können Sie Ihre Methodenlogik nicht sauberer schreiben.
quelle
Ein weiterer Ansatz, den Sie tun können, ist
Sobald Sie eine Funktion erstellt haben (in diesem Fall Lieferant), können Sie diese wie jede andere Variable weitergeben und mit aufrufen
Die Idee hier ist, ob Sie einen optionalen Wert haben oder nicht, ein internes Detail Ihrer Funktion und kein Parameter. Denkfunktionen beim Nachdenken über optional als Parameter sind tatsächlich sehr nützliche Techniken, die ich gefunden habe.
Die Frage, ob Sie es tatsächlich tun sollten oder nicht, hängt von Ihrer Präferenz ab, aber wie andere sagten, macht es Ihre API gelinde gesagt hässlich.
quelle
Anfangs habe ich es auch vorgezogen, Optionals als Parameter zu übergeben, aber wenn Sie von einer API-Designer-Perspektive zu einer API-User-Perspektive wechseln, sehen Sie die Nachteile.
In Ihrem Beispiel, in dem jeder Parameter optional ist, würde ich vorschlagen, die Berechnungsmethode wie folgt in eine eigene Klasse zu ändern:
quelle
Ich weiß, dass es bei dieser Frage eher um Meinungen als um harte Fakten geht. Aber ich bin kürzlich von einem .net-Entwickler zu einem Java-Entwickler gewechselt, deshalb bin ich erst kürzlich der optionalen Partei beigetreten. Ich würde es auch vorziehen, dies als Kommentar anzugeben, aber da meine Punktebene es mir nicht erlaubt, Kommentare abzugeben, bin ich gezwungen, dies stattdessen als Antwort zu verwenden.
Was ich getan habe, hat mir als Faustregel gute Dienste geleistet. Ist es, Optionals für Rückgabetypen zu verwenden und Optionals nur als Parameter zu verwenden, wenn ich sowohl den Wert des Optionals als auch das Wetter benötige oder nicht, hatte das Optionale einen Wert innerhalb der Methode.
Wenn ich mich nur um den Wert kümmere, überprüfe ich vor dem Aufrufen der Methode isPresent. Wenn die Methode eine Protokollierung oder eine andere Logik enthält, die davon abhängt, ob der Wert vorhanden ist, übergebe ich gerne die Option.
quelle
Dies liegt daran, dass wir unterschiedliche Anforderungen an einen API-Benutzer und einen API-Entwickler haben.
Ein Entwickler ist dafür verantwortlich, eine genaue Spezifikation und eine korrekte Implementierung bereitzustellen. Wenn dem Entwickler bereits bekannt ist, dass ein Argument optional ist, muss die Implementierung korrekt damit umgehen, unabhängig davon, ob es sich um eine Null oder eine Option handelt. Die API sollte für den Benutzer so einfach wie möglich sein, und null ist die einfachste.
Andererseits wird das Ergebnis vom API-Entwickler an den Benutzer übergeben. Obwohl die Spezifikation vollständig und ausführlich ist, besteht immer noch die Möglichkeit, dass der Benutzer sie entweder nicht bemerkt oder nur faul damit umgeht. In diesem Fall zwingt das optionale Ergebnis den Benutzer, zusätzlichen Code zu schreiben, um mit einem möglichen leeren Ergebnis umzugehen.
quelle
Wenn Sie Methode 3 verwenden, können Sie zunächst die letzten 14 Codezeilen durch folgende ersetzen:
int result = myObject.calculateSomething(p1.orElse(null), p2.orElse(null));
Die vier Variationen, die Sie geschrieben haben, sind Convenience- Methoden. Sie sollten sie nur verwenden, wenn sie bequemer sind. Das ist auch der beste Ansatz. Auf diese Weise ist der API sehr klar, welche Mitglieder erforderlich sind und welche nicht. Wenn Sie nicht vier Methoden schreiben möchten, können Sie die Dinge durch die Benennung Ihrer Parameter klären:
public int calculateSomething(String p1OrNull, BigDecimal p2OrNull)
Auf diese Weise ist klar, dass Nullwerte zulässig sind.
Ihre Verwendung von
p1.orElse(null)
zeigt, wie ausführlich unser Code bei Verwendung von Optional wird, weshalb ich ihn vermeide. Optional wurde für die funktionale Programmierung geschrieben. Streams brauchen es. Ihre Methoden sollten wahrscheinlich niemals Optional zurückgeben, es sei denn, Sie müssen sie für die funktionale Programmierung verwenden. Es gibt Methoden wieOptional.flatMap()
Methoden, die einen Verweis auf eine Funktion erfordern, die Optional zurückgibt. Hier ist seine Unterschrift:public <U> Optional<U> flatMap(Function<? super T, ? extends Optional<? extends U>> mapper)
Dies ist normalerweise der einzige gute Grund, eine Methode zu schreiben, die Optional zurückgibt. Aber auch dort kann es vermieden werden. Sie können einen Getter, der Optional nicht zurückgibt, an eine Methode wie flatMap () übergeben, indem Sie ihn in eine andere Methode einschließen, die die Funktion in den richtigen Typ konvertiert. Die Wrapper-Methode sieht folgendermaßen aus:
Angenommen, Sie haben einen Getter wie diesen:
String getName()
Sie können es nicht wie folgt an flatMap weitergeben:
opt.flatMap(Widget::getName) // Won't work!
Aber Sie können es so weitergeben:
opt.flatMap(optFun(Widget::getName)) // Works great!
Außerhalb der funktionalen Programmierung sollten Optionals vermieden werden.
Brian Goetz sagte es am besten, als er dies sagte:
Der Grund, warum Optional zu Java hinzugefügt wurde, ist folgender:
ist sauberer als das:
quelle