Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Was wäre die best practice beim überprüfen von Übergabe parameter?
Beispiel (dient nur zu veranschaulichung die Funktion könnte natürlich größer sein) - natürlich unterdem Geschichtspunkt von Solid:
Java:
public String myFunc(MyClass myClass, int value /* Bereich angenommen zwischen 1-100 */) {
return myClass.getParameter();
}
übergibt man der Funktion null so wird eine NullPointerException geworfen.
Es stellt sich jetzt die frage stelle ich von außen sicher dass niemals ein null übergeben wird, oder würde ich bei "größern" Funktionen eine Überprüfung der übergebenen Parameter machen?
Die Frage wäre hier, was die Methode im Fall des expliziten Prüfens dann tun würde, wenn z.B. null übergeben wird.
Du könntest hier statt einer NullPointerException eben z.B. eine IllegalArgumentException werfen.
Beides sind aber RuntimeExceptions, müssen also nicht deklariert und nicht gefangen werden.
Das heißt, im schlimmsten Fall gewinnt man dadurch gar nichts.
Und für NullPointerExceptions sind seit Java 11? die Exception-Meldungen ja auch schon ziemlich gut.
Anders sieht es bei Konsistenzprüfungen aus, wie z.B., dass ein Wert immer zwischen 10 und 20 sein muss, etc.
Ich bin es gewohnt, in Methoden ein Validierungsblock zu haben. Und in dem wird dann gezielt eine Exception geworfen. Sprich: if (argument == null) throw new NullPointerException();
Wenn es klare Regeln gibt, dann kann es Sinn machen, diese separat zu führen. Das wäre dann sowas wie: if(!isValidValue(value)) throw new ......
(Das ist ja meist etwas, das auch an mehreren Stellen benötigt wird!)
Das ist dann etwas, das in der Methode enthalten ist. Und gewisse Exceptions erben gedanklich ja von der EntwicklerIstBloedException.
Was bezüglich der NPE aber interessant ist und wo so viele ja immer bei anderen Sprachen das so positiv erwähnen: Null Sicherheit. Das kann man auch haben. @NonNull / @NotNull und @Nullable ... Dann prüft z.B. Spotbugs auch, dass da nichts, das Null sein kann, übergeben wird. Oder wenn etwas null sein kann, dann musst Du es prüfen sonst wird gemeckert.
Hintergrund dieser Prüfungen ist halt, dass ein Inkonsistenter Zustand erkannt wird. Den will man sofort stoppen. Wer weiß was noch nicht stimmig ist und was ggf. falsch läuft. Und je näher man an der Ursache ist, desto leichter findet man diese.
Ich bin es gewohnt, in Methoden ein Validierungsblock zu haben. Und in dem wird dann gezielt eine Exception geworfen. Sprich: if (argument == null) throw new NullPointerException();
Es stellt sich jetzt die frage stelle ich von außen sicher dass niemals ein null übergeben wird, oder würde ich bei "größern" Funktionen eine Überprüfung der übergebenen Parameter machen?
Sollte die Methode zu einer Klasse gehören, die du auch in anderen Projekten verwenden oder die du für die Allgemeinheit zur Verfügung stellen möchtest und die nur korrekt funktioniert, wenn gewisse Bedingungen stimmen, dann sollte die Klasse diese auch prüfen und mit entsprechenden Exceptions reagieren. Einfach nur, damit es nicht zu einer Ausführung kommt, mit einem ungewolltem/falschem Ergebnis.
Gleichzeitig kann es allerdings auch für das Programm, das die Klasse verwendet, sinnvoll sein, die Wertebereiche vorher zu prüfen. Ein Benutzer soll beispielsweise eine fehlerhafte Eingabe wiederholen können, ohne, dass er Ausnahmen um die Ohren geworfen bekommt. Ja, die Ausnahme könnte man fangen und dann die Eingabe wiederholen lassen, aber i. d. R. sollte man Exceptions nicht zur Programmsteuerung verwenden.
Schade, ich hätte doch auf ein paar Erläuterungen gehofft.
Ich sehe halt wirklich kein Problem. Meinst Du mit Abhängigkeit:
Die Einbindung dieser Annotations in das Projekt? Teilweise ist das schon direkt mit drin (z.B. Spring mit org.springframework.lang Namespace) oder man braucht keine Library, weil man die zwei Annotations auch direkt selbst in sein Code packen könnte. Müssen ja nur für die Auswertung da sein.
das Tool, dass die statische Codeanalyse macht? Also z.B. Spotbugs? Da sehe ich auch nicht wirklich ein Problem - das sind ja einfache Tool Abhängigkeiten.
Daher liegt es zumindest für mich nicht auf der Hand. Und eine systematische Benutzung dieser Annotations führt dann im Anschluss dazu, dass man eben keine NPEs mehr bekommen kann. Das kann man ja durchaus wollen und als sinnvoll erachten.
Das Codebeispiel war schlicht falsch. Es wird natürlich nicht manuell eine NPE geworfen. Es wird eine IllegalArgumentException geworfen. Denn genau das ist das Problem: Das Argument entspricht nicht der dokumentierten Schnittstelle.
Ich kann die Non-Null Annotationen + SpotBugs nur empfehlen. Wir nutzen die schon länger in der Firma. Dabie mit Default NonNull in der package-info, was die Lesbarkeit erhöht. Damit müssen nur die Ausnahmen annotiert werden. Und da nutzen wir auch konsequent CheckForNull und nicht Nullable, weil CheckForNull deutlich stärker ist. Es zwingt einen beim Zugriff auf null zu prüfen, während nullable das dem Programmier freistellt.
Ich sehe da zwei riesige Vorteile:
a) Die Wahrscheinlichkeit von NPEs wird deutlich verringert.
b) Es sorgt für eine saubere API. Zig-Null Checks einzubauen um die spotBugs Findings (die korrekt sind!) wegzubekommen ist lästiger und aufwändiger als eine saubere API zu bauen, die sicherstellt, dass ich keine Null-Checks brauche.
Ansonsten nutzen wir von Google Guava die PreConditions (https://guava.dev/releases/19.0/api/docs/com/google/common/base/Preconditions.html) weil das erlaubt es die Checks am Anfang der Methode kürzer zu schreiben, so dass ich kein if-Statement brauche und der Code wird lesbarer. Wer die Abhängigkeit nicht will (allerdings ist oft eh da), kann sich so was auch schnell selber bauen.
Es wird nicht immer alles konsequent genutzt, aber insbesondere bei public API die von anderen Komponenten verwendet wird, hat es sich bewährt.
Ich kann die Non-Null Annotationen + SpotBugs nur empfehlen. Wir nutzen die schon länger in der Firma. Dabie mit Default NonNull in der package-info, was die Lesbarkeit erhöht. Damit müssen nur die Ausnahmen annotiert werden. Und da nutzen wir auch konsequent CheckForNull und nicht Nullable, weil CheckForNull deutlich stärker ist. Es zwingt einen beim Zugriff auf null zu prüfen, während nullable das dem Programmier freistellt.
Ich sehe da zwei riesige Vorteile:
a) Die Wahrscheinlichkeit von NPEs wird deutlich verringert.
b) Es sorgt für eine saubere API. Zig-Null Checks einzubauen um die spotBugs Findings (die korrekt sind!) wegzubekommen ist lästiger und aufwändiger als eine saubere API zu bauen, die sicherstellt, dass ich keine Null-Checks brauche.
Ansonsten nutzen wir von Google Guava die PreConditions (https://guava.dev/releases/19.0/api/docs/com/google/common/base/Preconditions.html) weil das erlaubt es die Checks am Anfang der Methode kürzer zu schreiben, so dass ich kein if-Statement brauche und der Code wird lesbarer. Wer die Abhängigkeit nicht will (allerdings ist oft eh da), kann sich so was auch schnell selber bauen.
Es wird nicht immer alles konsequent genutzt, aber insbesondere bei public API die von anderen Komponenten verwendet wird, hat es sich bewährt.
Verstehe deine Aussage nicht so ganz. Könntest du mir ein Beispiel dafür geben, bitte?
Nachtrag: Ich würde gerne das, wenn eine Exception geworfen wird, auch eine Aufzeichnung in einem Log stattfindet z.B. durch Log4J. Ich habe aber noch nichts gefunden bzgl. zusammenspiel Guava und Log4J.
Da wäre meine Empfehlung: Spiel einmal etwas mit SpotBugs herum. In meinem Maven Projekt unter https://github.com/kneitzel/JavaMavenApp ist das schon alles eingebunden.
In Greeting habe ich bereits ein paar Annotations bezüglich NotNull - da kannst Du ja mal ein null Wert zuweisen. Schau einfach mal, was da Spotbugs für Meldungen bringt. (Log findet sich im target Verzeichnis. Die Zeilenumbrüche sind nicht so toll - da einfach mal die XML Datei von IntelliJ formatieren lassen (Oder eben von Deiner IDE - sollte jede IDE können).
Nachtrag: Ich würde gerne das, wenn eine Exception geworfen wird, auch eine Aufzeichnung in einem Log stattfindet z.B. durch Log4J. Ich habe aber noch nichts gefunden bzgl. zusammenspiel Guava und Log4J.
Du kannst überall, wo Du ein throw baust ja auch gerne etwas ins Log schreiben. Das ist zwar (im anderen Thread? Oder täuscht mich meine Erinnerung) als Anti Pattern bezeichnet worden (So ich mich nicht irre), aber das sind harte Worte. In der Regel ist es nicht notwendig - und wenn die Nachricht gleich ist, dann sollte die Exception irgendwo ja auch gefangen werden und damit im Log landen. Daher hast Du eine Information doppelt geschrieben.
Aber Anti Pattern ist ein starkes Wort. Es kann durchaus sein, dass Du beim Werfen der Exception mehr oder andere Informationen schreiben willst, die dann ggf. in einem eigenständigen Log landen können. Das ginge dann ggf. etwas Richtung Tracing oder so.
Was da Sinn macht oder eben nicht kannst nur Du entscheiden. Und technisch spricht da überhaupt nichts gegen.
Da wäre meine Empfehlung: Spiel einmal etwas mit SpotBugs herum. In meinem Maven Projekt unter https://github.com/kneitzel/JavaMavenApp ist das schon alles eingebunden.
In Greeting habe ich bereits ein paar Annotations bezüglich NotNull - da kannst Du ja mal ein null Wert zuweisen. Schau einfach mal, was da Spotbugs für Meldungen bringt. (Log findet sich im target Verzeichnis. Die Zeilenumbrüche sind nicht so toll - da einfach mal die XML Datei von IntelliJ formatieren lassen (Oder eben von Deiner IDE - sollte jede IDE können).
Du kannst überall, wo Du ein throw baust ja auch gerne etwas ins Log schreiben. Das ist zwar (im anderen Thread? Oder täuscht mich meine Erinnerung) als Anti Pattern bezeichnet worden (So ich mich nicht irre), aber das sind harte Worte. In der Regel ist es nicht notwendig - und wenn die Nachricht gleich ist, dann sollte die Exception irgendwo ja auch gefangen werden und damit im Log landen. Daher hast Du eine Information doppelt geschrieben.
Aber Anti Pattern ist ein starkes Wort. Es kann durchaus sein, dass Du beim Werfen der Exception mehr oder andere Informationen schreiben willst, die dann ggf. in einem eigenständigen Log landen können. Das ginge dann ggf. etwas Richtung Tracing oder so.
Was da Sinn macht oder eben nicht kannst nur Du entscheiden. Und technisch spricht da überhaupt nichts gegen.
Ich habe noch nichts über Anti-Pattern geschrieben, zumindest nicht das ich wüsste
Um es nochmal zu verdeutlichen, mir geht es darum, dass im Fehlerfall (im Produktiv - Einsatz) eine Exception geworfen wird, diese Informationen zum, wie du schon richtig sagtest tracing - dem späteren Nachverfolgen in einer Datei landen soll, die ich mir ggf. später ansehen kann.
Um es nochmal zu verdeutlichen, mir geht es darum, dass im Fehlerfall (im Produktiv - Einsatz) eine Exception geworfen wird, diese Informationen zum, wie du schon richtig sagtest tracing - dem späteren Nachverfolgen in einer Datei landen soll, die ich mir ggf. später ansehen kann.
Ja, ich denke, dass dies so durchaus verstanden wurde.
Und das, was Du in dem anderen Thread als mögliche Lösung geschrieben hast, geht technisch:
Java:
String message = "CountryService::createCountry(" + creator + ", " + country + "): The creator must not be null";
logger.error(message);
throw new NotDefinedException(message);
Aber wenn sowas als Bad Practice bezeichnet wird, dann wird uns ja irgendwas aufstoßen.
Wenn Du da so eine Exception wirfst, dann sollte diese irgendwo gefangen werden. Es wird also etwas geben wie:
(Das String Literal wäre da natürlich mit etwas sinnvollerem Inhalt gefüllt und nicht nur ein "Something bad happend!" )
Wichtig ist: Du gibst in dem catch auch die Exception mit. Die landet da also auch im Log. Damit hättest Du eine Meldung gleich zwei Mal in dem Log:
a) Beim werfen der Exception
b) Beim fangen der Exception
Daher ist das so erst einmal nicht ganz so toll.
Was kann also Sinn machen?
Ich sehe hier vor allem unterschiedliche Informationen. D.h. Du hast etwas wie:
Code:
log.error("Details, die auf dem Level der Methode / Klasse wichtig sind.");
log.warn("Noch mehr Details - auf anderen Levels .... bis hin zu tiefen Details auf Trace Ebene");
throw new GanzTolleException("High Level Beschreibung.")
Die Kernidee ist ja, dass Du unterschiedliche Level hast. Wieder typisches Auto Level:
Der Motor hat ein Problem. Die ganzen Details kann der Motor dann Loggen / Tracen. Das sind dann aber Low Leven Informationen, wozu man die Internas des Motors kennen muss. Irgendwas ist mit eine Zylinderkopfdichtung oder so.
Nach außen gibt es aber dann ein allgemeineres Problem. Das Auto zeigt also nur an: Fehlfunktion des Motors.
Das findet sich dann an unterschiedlichen Stellen. Das "Motor Log" ist nur mit speziellem Gerät auslesbar und so. Das andere findet sich direkt als Warnlampe mit kurzem Text im Amaturenbrett.
(Vergleich hinkt etwas - aber es wird vielleicht deutlich, was gemeint ist.)
Sowas macht aber auch nur dann Sinn, wenn Du sozusagen unterschiedliche Module hast. Die dann unterschiedlich konfiguriert werden bezüglich Logging. Du wirst innerhalb eines Bereiches sowas nicht machen. Da muss man nur einmal etwas loggen da alles ja auch in einer Datei landet.
Konnte diese Erklärung etwas helfen? Oder habe ich Dich evtl. falsch verstanden? Reden wir ggf. aneinander vorbei?
Ja, ich denke, dass dies so durchaus verstanden wurde.
Und das, was Du in dem anderen Thread als mögliche Lösung geschrieben hast, geht technisch:
Java:
String message = "CountryService::createCountry(" + creator + ", " + country + "): The creator must not be null";
logger.error(message);
throw new NotDefinedException(message);
Aber wenn sowas als Bad Practice bezeichnet wird, dann wird uns ja irgendwas aufstoßen.
Wenn Du da so eine Exception wirfst, dann sollte diese irgendwo gefangen werden. Es wird also etwas geben wie:
(Das String Literal wäre da natürlich mit etwas sinnvollerem Inhalt gefüllt und nicht nur ein "Something bad happend!" )
Wichtig ist: Du gibst in dem catch auch die Exception mit. Die landet da also auch im Log. Damit hättest Du eine Meldung gleich zwei Mal in dem Log:
a) Beim werfen der Exception
b) Beim fangen der Exception
Daher ist das so erst einmal nicht ganz so toll.
Was kann also Sinn machen?
Ich sehe hier vor allem unterschiedliche Informationen. D.h. Du hast etwas wie:
Code:
log.error("Details, die auf dem Level der Methode / Klasse wichtig sind.");
log.warn("Noch mehr Details - auf anderen Levels .... bis hin zu tiefen Details auf Trace Ebene");
throw new GanzTolleException("High Level Beschreibung.")
Die Kernidee ist ja, dass Du unterschiedliche Level hast. Wieder typisches Auto Level:
Der Motor hat ein Problem. Die ganzen Details kann der Motor dann Loggen / Tracen. Das sind dann aber Low Leven Informationen, wozu man die Internas des Motors kennen muss. Irgendwas ist mit eine Zylinderkopfdichtung oder so.
Nach außen gibt es aber dann ein allgemeineres Problem. Das Auto zeigt also nur an: Fehlfunktion des Motors.
Das findet sich dann an unterschiedlichen Stellen. Das "Motor Log" ist nur mit speziellem Gerät auslesbar und so. Das andere findet sich direkt als Warnlampe mit kurzem Text im Amaturenbrett.
(Vergleich hinkt etwas - aber es wird vielleicht deutlich, was gemeint ist.)
Sowas macht aber auch nur dann Sinn, wenn Du sozusagen unterschiedliche Module hast. Die dann unterschiedlich konfiguriert werden bezüglich Logging. Du wirst innerhalb eines Bereiches sowas nicht machen. Da muss man nur einmal etwas loggen da alles ja auch in einer Datei landet.
Konnte diese Erklärung etwas helfen? Oder habe ich Dich evtl. falsch verstanden? Reden wir ggf. aneinander vorbei?
Ersteinmal bzgl. deinen Anmerkungen und z.B. Client via HTTP-Verbindung aus dem anderen Beitrag wäre ich voll und ganz bei euch. Wenn aber eine "automatischer" Ablauf passiert, z.B. ich habe eine Anwendung auf einem Server laufen, der sagen wir mal immer etwas überprüft (was auch immer dieses sein mag) und unter welchen Umständen auch immer, wird eine Exception geworfen, so muss ich ja beim "Ausfall" wissen, welche Exception mit welcher Meldung geworfen wurde (es muss ja nicht zwangsläufig zu einem Stillstand kommen), die ich mir im Nachhinein ansehen kann. Log - Ausgabe auf Console nützt mir persönlich nicht viel, wenn z.B. diese durch (z.B. neu hochfahren) verschwindet.