Nachdem ich Java 8 jetzt seit mehr als 6 Monaten verwende, bin ich ziemlich zufrieden mit den neuen API-Änderungen. Ein Bereich, in dem ich immer noch nicht sicher bin, ist der Zeitpunkt der Verwendung Optional
. Ich scheine zwischen dem Wunsch, es überall zu verwenden, wo etwas sein mag null
, und nirgendwo hin und her zu schwingen .
Es scheint viele Situationen zu geben, in denen ich es verwenden könnte, und ich bin mir nie sicher, ob es Vorteile bringt (Lesbarkeit / Nullsicherheit) oder nur zusätzlichen Aufwand verursacht.
Ich habe also ein paar Beispiele und würde mich für die Gedanken der Community interessieren, ob dies von Optional
Vorteil ist.
1 - Als Rückgabetyp für öffentliche Methoden, wenn die Methode Folgendes zurückgeben könnte null
:
public Optional<Foo> findFoo(String id);
2 - Als Methodenparameter, wenn der Parameter sein kann null
:
public Foo doSomething(String id, Optional<Bar> barOptional);
3 - Als optionales Mitglied einer Bohne:
public class Book {
private List<Pages> pages;
private Optional<Index> index;
}
4 - In Collections
:
Im Allgemeinen denke ich nicht:
List<Optional<Foo>>
fügt etwas hinzu - zumal man damit Werte usw. filter()
entfernen kann null
, aber gibt es Optional
in Sammlungen gute Verwendungsmöglichkeiten ?
Irgendwelche Fälle, die ich verpasst habe?
Map<Character, String>
. Wenn es keinen Ersatz gibt, kann ich dies verwenden :Optional.ofNullable(map.get(c)).orElse(String.valueOf(c))
. Beachten Sie auch, dass Optional aus Guava gestohlen wurde und eine viel schönere Syntax hat:Optional.fromNullable(map.get(c)).or(String.valueOf(c));
.filter(Optional::absent)
"Nullwerte"getOrDefault()
?Antworten:
Der Hauptpunkt von
Optional
besteht darin, ein Mittel für eine Funktion bereitzustellen, die einen Wert zurückgibt, um das Fehlen eines Rückgabewerts anzuzeigen. Siehe diese Diskussion . Dadurch kann der Aufrufer eine Kette fließender Methodenaufrufe fortsetzen.Dies entspricht am ehesten dem Anwendungsfall Nr. 1 in der Frage des OP. Das Fehlen eines Wertes ist jedoch eine genauere Formulierung als null, da so etwas
IntStream.findFirst
niemals null zurückgeben könnte.Für Anwendungsfall Nr. 2 , bei dem ein optionales Argument an eine Methode übergeben wird, könnte dies funktionieren, ist jedoch ziemlich ungeschickt. Angenommen, Sie haben eine Methode, die eine Zeichenfolge gefolgt von einer optionalen zweiten Zeichenfolge verwendet. Das Akzeptieren eines
Optional
als zweites Argument würde zu folgendem Code führen:Sogar Null zu akzeptieren ist schöner:
Am besten ist es wahrscheinlich, eine überladene Methode zu haben, die ein einzelnes Zeichenfolgenargument akzeptiert und einen Standard für das zweite bereitstellt:
Dies hat zwar Einschränkungen, ist aber viel schöner als die oben genannten.
Die Anwendungsfälle Nr. 3 und Nr. 4 , die
Optional
in einem Klassenfeld oder in einer Datenstruktur enthalten sind, werden als Missbrauch der API angesehen. Erstens widerspricht es dem Hauptentwurfsziel,Optional
wie oben angegeben. Zweitens bringt es keinen Mehrwert.Es gibt drei Möglichkeiten, mit dem Fehlen eines Werts in a umzugehen
Optional
: einen Ersatzwert bereitzustellen, eine Funktion aufzurufen, um einen Ersatzwert bereitzustellen, oder eine Ausnahme auszulösen. Wenn Sie in einem Feld speichern, tun Sie dies zum Zeitpunkt der Initialisierung oder Zuweisung. Wenn Sie einer Liste Werte hinzufügen, wie im OP erwähnt, haben Sie die zusätzliche Möglichkeit, den Wert einfach nicht hinzuzufügen, wodurch fehlende Werte "abgeflacht" werden.Ich bin sicher, jemand könnte sich einige erfundene Fälle einfallen lassen, in denen er wirklich einen
Optional
in einem Feld oder einer Sammlung aufbewahren möchte , aber im Allgemeinen ist es am besten, dies zu vermeiden.quelle
Optional
ein Feld zu haben, wenn Dinge zu tun sind oder nicht, wenn ein Wert vorhanden ist oder nicht.if(foo == null)
es besser wäre, intern zu arbeiten, als nur das Feld als zu speichernoptional
. Und ich verstehe nicht, warum explizitesgetOptionalFoo()
internes Aufrufen besser ist, als nur das Feld als zu speichernOptional
. Wenn ein Feld sein kannnull
und ein Feld nicht sein kannnull
, warum sollte man dies dem Compiler nicht mitteilen, indem man sie erstelltOptional
oder nichtOptional
?Optional<>
Experten höre : "NichtOptional<>
auf einem Feld lagern ". Ich versuche wirklich, den Sinn dieser Empfehlung zu verstehen. Stellen Sie sich einen DOM-Baum vor, in dem ein Knoten ein übergeordnetes Element haben könnte oder nicht. Es scheint innerhalb des AnwendungsfallsNode.getParent()
zurückzukehrenOptional<Node>
. Soll ich wirklichnull
jedes Mal ein speichern und das Ergebnis verpacken? Warum? Was bringt mir diese zusätzliche Ineffizienz, außer dass mein Code hässlich aussieht?Optional<Node> getParent() { return Optional.ofNullable(parent); }
. Das sieht teuer aus, weil esOptional
jedes Mal eine zuweist! Wenn der Anrufer es jedoch sofort auspackt, ist das Objekt äußerst kurzlebig und wird niemals aus dem Eden-Raum befördert. Möglicherweise wird es sogar durch die Fluchtanalyse der JIT beseitigt. Die Antwort lautet unter dem Strich wie immer "es kommt darauf an", aber die VerwendungOptional
in Feldern führt möglicherweise zu einer Aufblähung der Speichernutzung und verlangsamt die Durchquerung der Datenstruktur. Und schließlich denke ich, dass es den Code durcheinander bringt, aber das ist Geschmackssache.Ich bin zu spät zum Spiel, aber für das, was es wert ist, möchte ich meine 2 Cent hinzufügen. Sie widersprechen dem Designziel von
Optional
, das in Stuart Marks 'Antwort gut zusammengefasst ist , aber ich bin (offensichtlich) immer noch von ihrer Gültigkeit überzeugt.Überall optional verwenden
Allgemein
Ich habe einen ganzen Blog-Beitrag über die Verwendung geschrieben,
Optional
aber im Grunde kommt es darauf an:Optional
anstelle von verwendet werdennull
Die ersten beiden Ausnahmen können den wahrgenommenen Aufwand für das Ein- und Auspacken von Referenzen verringern
Optional
. Sie werden so gewählt, dass eine Null niemals legal eine Grenze von einer Instanz in eine andere übertragen kann.Beachten Sie, dass dies fast nie
Optional
s in Sammlungen zulässt, die fast so schlecht sind wienull
s. Tu es einfach nicht. ;)In Bezug auf Ihre Fragen
Vorteile
Auf diese Weise wird das Vorhandensein von
null
s in Ihrer Codebasis verringert , obwohl sie nicht gelöscht werden. Aber das ist nicht einmal der Hauptpunkt. Es gibt andere wichtige Vorteile:Klärt die Absicht
Die Verwendung
Optional
drückt deutlich aus, dass die Variable optional ist. Jeder Leser Ihres Codes oder Verbraucher Ihrer API wird über den Kopf geschlagen, weil dort möglicherweise nichts vorhanden ist und eine Überprüfung erforderlich ist, bevor auf den Wert zugegriffen werden kann.Entfernt Unsicherheit
Ohne
Optional
die Bedeutung einesnull
Ereignisses ist unklar. Dies kann eine rechtliche Darstellung eines Zustands (sieheMap.get
) oder ein Implementierungsfehler wie eine fehlende oder fehlgeschlagene Initialisierung sein.Dies ändert sich dramatisch mit der anhaltenden Verwendung von
Optional
. Hier bedeutet bereits das Auftreten vonnull
das Vorhandensein eines Fehlers. (Wenn der Wert fehlen würde,Optional
wäre ein Wert verwendet worden.) Dies erleichtert das Debuggen einer Nullzeigerausnahme erheblich, da die Frage nach der Bedeutung dieser Ausnahmenull
bereits beantwortet ist.Weitere Null-Checks
Jetzt, wo nichts mehr sein
null
kann, kann dies überall durchgesetzt werden. Ob bei Anmerkungen, Zusicherungen oder einfachen Überprüfungen, Sie müssen nie darüber nachdenken, ob dieses Argument oder dieser Rückgabetyp null sein kann. Es kann nicht!Nachteile
Natürlich gibt es keine Silberkugel ...
Performance
Das Umschließen von Werten (insbesondere Grundelementen) in eine zusätzliche Instanz kann die Leistung beeinträchtigen. In engen Schleifen kann dies spürbar oder sogar noch schlimmer werden.
Beachten Sie, dass der Compiler möglicherweise die zusätzliche Referenz für kurzlebige Lebensdauern von
Optional
s umgehen kann . In Java 10 können Werttypen die Strafe weiter reduzieren oder entfernen.Serialisierung
Optional
ist nicht serialisierbar, aber eine Problemumgehung ist nicht übermäßig kompliziert.Invarianz
Aufgrund der Invarianz generischer Typen in Java werden bestimmte Vorgänge umständlich, wenn der tatsächliche Werttyp in ein generisches Typargument verschoben wird. Hier wird ein Beispiel gegeben (siehe "Parametrischer Polymorphismus") .
quelle
List
s zu speichern . Dies ist der Fall, wenn es wichtig ist, dass sich ein bestimmtes Element an einem bestimmten Index befindet, das Element jedoch vorhanden sein kann oder nicht. Das wird durch einenList<Optional<T>>
Typ klar kommuniziert . Wenn es andererseits nur wichtig ist, welche Objekte Mitglieder einer Sammlung sind, dann gibt es keinen Sinn.Optional
Wesen, das an eine Methode übergeben wird, kann seinnull
. Was hast du gewonnen? Jetzt müssen Sie zwei Prüfungen durchführen. Siehe stackoverflow.com/a/31923042/650176Optional
(was der Fall sein sollte, wenn Sie bereit sind, es als Argumente weiterzugeben)null
. Das Aufrufen einer Methode mit einem expliziten Parameternull
ist also offensichtlich ein Fehler.Persönlich bevorzuge ich die Verwendung von IntelliJs Code Inspection Tool , um diese zu verwenden
@NotNull
und zu@Nullable
überprüfen, da dies größtenteils Kompilierungszeit ist (einige Laufzeitprüfungen können). Dies hat einen geringeren Overhead in Bezug auf die Lesbarkeit des Codes und die Laufzeitleistung. Es ist nicht so streng wie die Verwendung von Optional, jedoch sollte dieser Mangel an Genauigkeit durch anständige Komponententests untermauert werden.Dies funktioniert mit Java 5 und es ist nicht erforderlich, Werte zu verpacken und zu entpacken. (oder Wrapper-Objekte erstellen)
quelle
@Nonnull
persönlich - arbeitet mit FindBugs;)@Nonnull @NotNull etc
Ich denke, die Guava Optional und ihre Wiki-Seite bringen es ganz gut auf den Punkt:
Optional
fügt einige Overhead, aber ich glaube , ihr wesentlicher Vorteil daraus zu machen ist explizit , dass ein Objekt und es erzwingt möglicherweise nicht vorhanden sein , dass die Programmierer mit der Situation umgehen. Es verhindert, dass jemand den geliebten!= null
Scheck vergisst .Am Beispiel von 2 denke ich, dass es viel expliziter ist, Code zu schreiben:
als
Für mich
Optional
ist es umso besser, dass keine Soundkarte vorhanden ist.Meine 2 ¢ über deine Punkte:
public Optional<Foo> findFoo(String id);
- Da bin ich mir nicht sicher. Vielleicht würde ich eine zurückgeben,Result<Foo>
die leer sein oder eine enthalten könnteFoo
. Es ist ein ähnliches Konzept, aber nicht wirklich einOptional
.public Foo doSomething(String id, Optional<Bar> barOptional);
- Ich würde @Nullable und einen Findbugs-Check bevorzugen, wie in Peter Lawreys Antwort - siehe auch diese Diskussion .Optional<Index> getIndex()
um explizit anzugeben, dass das Buch möglicherweise keinen Index hat.Im Allgemeinen würde ich versuchen, das Weitergeben von
null
s zu minimieren . (Einmal verbrannt ...) Ich denke, es lohnt sich, die entsprechenden Abstraktionen zu finden und den anderen Programmierern anzuzeigen, was ein bestimmter Rückgabewert tatsächlich darstellt.quelle
soundcard.ifPresent(System.out::println)
. Das AufrufenisPresent
ist semantisch dasselbe wie das Suchen nachnull
.if(soundcard != null && soundcard.isPresent())
. Obwohl ich hoffe, dass niemand jemals eine API erstellt, die eine Option zurückgibt und auch Null zurückgeben könnte.Aus dem Oracle-Tutorial :
quelle
Hier ist ein guter Artikel , der die Nützlichkeit von Anwendungsfall 1 zeigt. Dort dieser Code
wird dazu transformiert
durch Verwendung von Optional als Rückgabewert der jeweiligen Getter- Methoden.
quelle
Hier ist eine interessante Verwendung (glaube ich) für ... Tests.
Ich beabsichtige, eines meiner Projekte intensiv zu testen, und baue daher Aussagen auf. Nur gibt es Dinge, die ich überprüfen muss und andere nicht.
Ich baue daher Dinge, um sie zu behaupten, und verwende eine Behauptung, um sie zu verifizieren, wie folgt:
In der NodeAssert-Klasse mache ich Folgendes:
Was bedeutet, dass die Behauptung wirklich nur ausgelöst wird, wenn ich das Etikett überprüfen möchte!
quelle
Optional
Mit class können Sie die Verwendung vermeidennull
und eine bessere Alternative bereitstellen:Dies ermutigt den Entwickler, die Anwesenheit zu überprüfen, um nicht gefangene zu vermeiden
NullPointerException
.Die API wird besser dokumentiert, da erkennbar ist, wo die fehlenden Werte zu erwarten sind.
Optional
bietet eine praktische API für die weitere Arbeit mit dem Objekt :isPresent()
;get()
;;orElse()
;;orElseGet()
;;orElseThrow()
;;map()
;;filter()
;;flatmap()
.Darüber hinaus verwenden viele Frameworks diesen Datentyp aktiv und geben ihn von ihrer API zurück.
quelle
Verwenden Sie sie in Java nur, wenn Sie süchtig nach funktionaler Programmierung sind.
Sie haben keinen Platz als Methodenargumente (ich behaupte, jemand wird Ihnen eines Tages eine Null-Option übergeben, nicht nur eine Option, die leer ist).
Sie sind für Rückgabewerte sinnvoll, laden jedoch die Client-Klasse ein, die Kette zur Verhaltensbildung weiter auszudehnen.
FP und Ketten haben in einer imperativen Sprache wie Java wenig Platz, da das Debuggen und nicht nur das Lesen sehr schwierig ist. Wenn Sie zur Zeile treten, können Sie weder den Status noch die Absicht des Programms kennen. Sie müssen einsteigen, um es herauszufinden (in Code, der oft nicht Ihnen gehört, und viele Stapelrahmen tief trotz Schrittfiltern), und Sie müssen viele Haltepunkte hinzufügen, um sicherzustellen, dass er in dem von Ihnen hinzugefügten Code / Lambda anhalten kann. anstatt einfach die trivialen Zeilen if / else / call zu durchlaufen.
Wenn Sie funktionale Programmierung wünschen, wählen Sie etwas anderes als Java und hoffen, dass Sie die Tools zum Debuggen haben.
quelle
Ich denke nicht, dass Optional ein allgemeiner Ersatz für Methoden ist, die möglicherweise Nullwerte zurückgeben.
Die Grundidee lautet: Das Fehlen eines Wertes bedeutet nicht, dass er möglicherweise in Zukunft verfügbar ist. Es ist ein Unterschied zwischen findById (-1) und findById (67).
Die Hauptinformation von Optionals für den Anrufer ist, dass er möglicherweise nicht auf den angegebenen Wert zählt, dieser jedoch möglicherweise irgendwann verfügbar ist. Vielleicht verschwindet es wieder und kommt später noch einmal zurück. Es ist wie ein Ein / Aus-Schalter. Sie haben die "Option", das Licht ein- oder auszuschalten. Sie haben jedoch keine Option, wenn Sie kein Licht zum Einschalten haben.
Daher finde ich es zu chaotisch, Optionals überall dort einzuführen, wo zuvor möglicherweise null zurückgegeben wurde. Ich werde weiterhin null verwenden, aber nur in eingeschränkten Bereichen wie der Wurzel eines Baumes, der verzögerten Initialisierung und expliziten Suchmethoden.
quelle
Scheint
Optional
ist nur dann sinnvoll , wenn der Typ T in Optional ein primitiver Typ wie istint
,long
,char
, etc. Für „echte“ Klassen, es macht keinen Sinn für mich machen , wie Sie einen verwenden könnennull
sowieso Wert.Ich denke, es wurde von hier (oder von einem anderen ähnlichen Sprachkonzept) übernommen.
Nullable<T>
In C # wurde dies
Nullable<T>
vor langer Zeit eingeführt, um Werttypen zu verpacken.quelle
Optional
in der Tatjava.util.Optional
.An hat eine ähnliche Semantik wie eine nicht modifizierbare Instanz des Iterator-Entwurfsmusters :
Optional
isPresent()
)get()
), wenn es sich auf ein Objekt beziehtnext()
Methode).Erwägen Sie daher, einen
Optional
Kontext zurückzugeben oder zu übergeben, in dem Sie zuvor möglicherweise die Verwendung eines Java in Betracht gezogen habenIterator
.quelle
Java SE 8 führt eine neue Klasse namens java.util.Optional ein.
Sie können ein leeres optionales oder optionales Element mit dem Wert Null erstellen.
Und hier ist eine Option mit einem Wert ungleich Null:
Tun Sie etwas, wenn ein Wert vorhanden ist
Nachdem Sie über ein optionales Objekt verfügen, können Sie auf die verfügbaren Methoden zugreifen, um das Vorhandensein oder Fehlen von Werten explizit zu behandeln. Anstatt sich daran zu erinnern, eine Nullprüfung durchzuführen, gehen Sie wie folgt vor:
Sie können die ifPresent () -Methode wie folgt verwenden:
quelle