[QUOTE=SlaterB]wenn null irgendwo durchkommt, auch in die DB ohne Constraint, dann ist der Wert vielleicht auch erlaubt,
oder ist neuerdings NOT NULL eine Standard-Constraint aller Attribute aller Tabellen?
wie sieht es dazu eigentlich im fJorum aus?
wie ich gerade sehe hat die ROOT-Category null als parent, wird sich das noch konzeptionell ändern oder akzeptabler null-Einsatz?[/quote]
Was soll sonst als Parent angegeben werden? Ich hatte ursprünglich versucht, auf sich selbst zu referenzieren, aber das hat Hibernate gar nicht gern gesehen.
null-Checks braucht es an wichtigen Stellen, aber wenn man sie vergisst kracht es doch in der Regel unmittelbar,
wenn man dagegen ein orElseThrow() vergisst kann das ganz schön böse enden… :
Oh Mann, das ist doch gerade der Punkt: Du musst selbst etwas tun, um den Wert aus dem Optional herauszuholen. Und da hast du die Wahl, was du bei leerem Rückgabewert tust: selbst eine Exception werfen (orElseThrow), einen Defaultwert angeben (orElse, orElseGet), oder eine Exception riskieren, wenn du get verwendest (was du in meinem Code nicht finden wirst).
vielleicht etwas konstruiertes Beispiel, bei dir noch meist Rückgabewerte dabei, die das verhindern
return Optional.ofNullable(null);
}
public void doIt() {
get().map(str -> createSomething(str)); // .orElseThrow(() -> new RuntimeException());
}
String createSomething(String st) {
System.out.println("important thing created: " + st);
return "";
}
unsichtbarer Bug: eine wichtige Aktion wird nicht ausgeführt, keine Fehlermeldung, vermeintlich normaler Erfolgsausgang
Sehr konstruiert. map ist nicht dafür da, eine Aktion auszuführen, sondern einen Wert zu transformieren. Hier hättest du stattdessen die Möglichkeit, es mit ifPresent richtig zu machen (leider gibt es keine Variante, die eine Exception im „leeren“ Fall wirft)
richtig schlimm wird Optional bei Dauereinsatz wie anfangs angedacht
Optional<FlashScope> flashScope = Optional.ofNullable(context.getFlashScope());
was praktisch überall auftrat,
aktuell zum Glück nicht, bei den Anlege-Stellen müsste alternativ auch geprüft werden,
wird sich zeigen wie es weitergeht in der Code-Breite,
etwa bei Verwendungen von Klassen wie Map, vorher 10 Dinge eingefügt, nachher diese 10 Dinge wieder benötigt,
nicht zu testen ob auch vorhanden, eine Zeile später sonst NullPointerException,
da kann man die Hälfe des Codes mit eigenen Exception vollschreiben oder auf guten Verlauf vertrauen
Scala hat eine Map.getOpt Methode, die Option liefert. Habe bis jetzt noch keine Beschwerden gehört.
ich sehe übrigens erstaunlich viele Stellen a la
findRole(ROLE.ROLE_OWNER.name()).
orElseThrow(RuntimeException::new);
user.getRoles().add(owner_role);
gar keine große Mühe auf eine genaue Fehlermeldung, kein wichtiger Fehler, einfach nur generisches Äquivalent für eine NullPointerException,
mal abgesehen davon dass ansonsten vielleicht die null hinzugefügt werden würde,
Test hier nötig (besser aber eine Methode findRoleMandatory/ NotNull(), die bereits die Exception wirft, nicht an vielleicht bald zig-Codestellen mit orElseThrow() )
Wie ich schon schrub, ist das System mitten in der Entwicklung, und die Fehlerbehandlung noch ziemlich wirr bis nicht vorhanden. Ich muss erst einmal sehen, wo und wie ich die Fehler abfange, wie das Logging geschehen soll, ob das mit den FlashMessages so in Ordnung ist u.s.w. Das wird auf keinen Fall so bleiben, nur versuche ich vorrangig, etwas Vorzeigbares zu produzieren, bevor ich mich auf sowas konzentriere (Testing ist momentan genau so ein düsteres Kapitel).
wie passt das eigentlich zum Thema
http://forum.byte-welt.net/java-forum-das-java-welt-kompetenz-zentrum-wir-wissen-und-helfen-/allgemeine-themen/16681-streitfrage-fachliche-exceptions.html
mit @Bleiglanz unerbittlicher Meinung, dass keinerlei eigene Exceptions für Fachlichkeiten wie nicht gefundene Objekte nötig sind,
alles auch über Rückgabewerte ginge, was ja auch hier sicher theoretisch möglich ist
planst du da noch Änderungen irgendwann oder stimmen wir mal überein, RuntimeExceptions überall zum Ausgangspunkt einer Aktion gute Sache?
Exceptions sind nun einmal in vielen Frameworks vorgesehen, und fjorum nutzt Spring sehr weitreichend, also sehe ich das etwas pragmatisch. Prinzipiell hat Bleiglanz recht, es geht auch ohne (z.B. mit dem schon genannten Try aus try4j), aber ich glaube nicht, dass ich das für fjorum flächendeckend einsetzen werde.
falls du das Aktuelle dazu meinst, dann wären Listen & komplizierte Trees ja noch eine Sache, die es aber bisher kaum gibt,
aber die Verwendung nur für Optionals, als es noch da war
map(topic -> userService.getById(form.getUserId())
des zuvor geladenen optionalen Topic auf optionalen User ist wohl kaum ‚kontrollierte Umwandlung Foo in ein Foo‘,
sondern Aneinanderreihung getrennter unabhängiger Lade-Vorgänge
dafür die wichtige map()-Syntax zu nutzen, die komplizierte Listen, Abhängigkeit von X auf Y suggeriert, ist gefählich inflationär,
aber mit Option wohl kaum anders machbar wenn nicht wirklich häßlicher Code daraus werden soll, Zwickmühle, Nachteil
Ich verstehe deine Argumentation nicht. Optional ist ja im Prinzip eine Liste, nur mit einer Maximalkapazität von 1. Warum sollte es sich nicht so verhalten? Was ist daran „inflationär“?
Und natürlich gibt es eine Abgängigkeit von X und Y, du musst map ja eine Function<X,Y> liefern. Und map „suggeriert“ auch nichts, sondern verspricht etwas (nämlich dass Foo ein Funktor ist, und sich entsprechend verhält).
Nebenbei bemerkt könnte man für sowas
topicService.getById(form.getTopicId()).
flatMap(topic -> userService.getById(form.getUserId()).
map(user -> createNewReply(topic, user, form.getContent()))).
orElseThrow(() -> new DataIntegrityViolationException("Topic or user not found"));
auch eine Helper-Klasse schreiben (hatte ich schon), die es etwas symmetrischer und lesbarer macht (auch wenn es etwas „rückwärts“ aussieht):
Optionals.lift((topic, user) -> createNewReply(topic, user, form.getContent())).
apply(topicService.getById(form.getTopicId()), userService.getById(form.getUserId())).
orElseThrow(() -> new DataIntegrityViolationException("Topic or user not found"));
Dabei hätte lift den Typ BiFunction<Optional<A>, Optional<B>, Optional<C>> lift(BiFunction<A,B,C> fn)
.