Der Grund, warum Optional
Java hinzugefügt wurde, ist folgender:
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(...));
ist sauberer als das:
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;
Mein Punkt ist, dass Optional geschrieben wurde, um die funktionale Programmierung zu unterstützen , die gleichzeitig zu Java hinzugefügt wurde. (Das Beispiel stammt von einem Blog von Brian Goetz . Ein besseres Beispiel könnte die orElse()
Methode verwenden, da dieser Code ohnehin eine Ausnahme auslöst, aber Sie erhalten das Bild.)
Aber jetzt verwenden die Leute Optional aus einem ganz anderen Grund. Sie verwenden es, um einen Fehler im Sprachdesign zu beheben. Der Fehler ist folgender: Es gibt keine Möglichkeit anzugeben, welche Parameter und Rückgabewerte einer API null sein dürfen. Es kann in den Javadocs erwähnt werden, aber die meisten Entwickler schreiben nicht einmal Javadocs für ihren Code, und nicht viele werden die Javadocs beim Schreiben überprüfen. Dies führt zu einer Menge Code, der immer nach Nullwerten sucht, bevor er sie verwendet, obwohl sie oft nicht null sein können, da sie bereits neun- oder zehnmal im Aufrufstapel wiederholt validiert wurden.
Ich denke, es gab einen echten Durst, diesen Fehler zu beheben, weil so viele Leute, die die neue optionale Klasse sahen, davon ausgegangen sind, dass ihr Zweck darin bestand, APIs klarer zu machen. Aus diesem Grund stellen die Leute Fragen wie "Sollten Getter Optionals zurückgeben?" Nein, das sollten sie wahrscheinlich nicht, es sei denn, Sie erwarten, dass der Getter für die funktionale Programmierung verwendet wird, was sehr unwahrscheinlich ist. Wenn Sie sich ansehen, wo Optional in der Java-API verwendet wird, sind dies hauptsächlich die Stream-Klassen, die den Kern der funktionalen Programmierung bilden. (Ich habe nicht sehr gründlich nachgesehen, aber die Stream-Klassen sind möglicherweise der einzige Ort, an dem sie verwendet werden.)
Wenn Sie vorhaben, einen Getter in einem Teil des Funktionscodes zu verwenden, ist es möglicherweise eine gute Idee, einen Standard-Getter und einen zweiten zu haben, der Optional zurückgibt.
Oh, und wenn Ihre Klasse serialisierbar sein soll, sollten Sie Optional auf keinen Fall verwenden.
Optionale Optionen sind eine sehr schlechte Lösung für den API-Fehler, da a) sie sehr ausführlich sind und b) sie dieses Problem überhaupt nicht lösen sollten.
Eine viel bessere Lösung für den API-Fehler ist der Nullness Checker . Dies ist ein Annotationsprozessor, mit dem Sie angeben können, welche Parameter und Rückgabewerte null sein dürfen, indem Sie sie mit @Nullable annotieren. Auf diese Weise kann der Compiler den Code scannen und herausfinden, ob ein Wert, der tatsächlich null sein kann, an einen Wert übergeben wird, bei dem null nicht zulässig ist. Standardmäßig wird davon ausgegangen, dass nichts null sein darf, es sei denn, es ist mit Anmerkungen versehen. Auf diese Weise müssen Sie sich keine Gedanken über Nullwerte machen. Das Übergeben eines Nullwerts an einen Parameter führt zu einem Compilerfehler. Das Testen eines Objekts auf Null, das nicht Null sein kann, erzeugt eine Compiler-Warnung. Dies hat zur Folge, dass die NullPointerException von einem Laufzeitfehler in einen Fehler zur Kompilierungszeit geändert wird.
Das ändert alles.
Verwenden Sie für Ihre Getter nicht Optional. Und versuchen Sie, Ihre Klassen so zu gestalten, dass keines der Mitglieder möglicherweise null sein kann. Und vielleicht versuchen Sie, den Nullness Checker zu Ihrem Projekt hinzuzufügen und Ihre Getter und Setter-Parameter @Nullable zu deklarieren, wenn sie benötigt werden. Ich habe das nur mit neuen Projekten gemacht. Wahrscheinlich werden in bestehenden Projekten viele Warnungen ausgegeben, die mit vielen überflüssigen Nulltests geschrieben wurden. Daher kann eine Nachrüstung schwierig sein. Aber es wird auch viele Fehler fangen. Ich liebe es. Mein Code ist dadurch viel sauberer und zuverlässiger.
(Es gibt auch eine neue Sprache, die dies behebt. Mit Kotlin, das in Java-Bytecode kompiliert wird, können Sie angeben, ob ein Objekt beim Deklarieren null sein darf. Dies ist ein sauberer Ansatz.)
Nachtrag zum Originalbeitrag (Version 2)
Nachdem ich viel darüber nachgedacht habe, bin ich widerwillig zu dem Schluss gekommen, dass es akzeptabel ist, Optional unter einer Bedingung zurückzugeben: Dass der abgerufene Wert tatsächlich null sein könnte. Ich habe viel Code gesehen, in dem Leute routinemäßig Optional von Gettern zurückgeben, die unmöglich null zurückgeben können. Ich sehe dies als eine sehr schlechte Codierungspraxis, die dem Code nur Komplexität verleiht, was Fehler wahrscheinlicher macht. Wenn der zurückgegebene Wert jedoch tatsächlich null ist, schließen Sie ihn in eine Option ein.
Beachten Sie, dass Methoden, die für die funktionale Programmierung entwickelt wurden und eine Funktionsreferenz erfordern, in zwei Formen geschrieben werden (und sollten), von denen eine optional ist. Zum Beispiel Optional.map()
und Optional.flatMap()
beide nehmen Funktionsreferenzen. Der erste bezieht sich auf einen gewöhnlichen Getter und der zweite auf einen, der Optional zurückgibt. Sie tun also niemandem einen Gefallen, indem Sie eine Option zurückgeben, bei der der Wert nicht null sein kann.
Trotzdem sehe ich immer noch, dass der vom Nullness Checker verwendete Ansatz der beste Weg ist, um mit Nullen umzugehen, da sie NullPointerExceptions von Laufzeitfehlern umwandeln, um Zeitfehler zu kompilieren.