{"id":809,"date":"2016-01-02T11:29:26","date_gmt":"2016-01-02T09:29:26","guid":{"rendered":"http:\/\/invidit.de\/blog\/?p=809"},"modified":"2021-03-25T19:48:28","modified_gmt":"2021-03-25T17:48:28","slug":"total-optional","status":"publish","type":"post","link":"https:\/\/invidit.de\/blog\/total-optional\/","title":{"rendered":"Total Optional"},"content":{"rendered":"\n<p>Hallo Spa\u00df-Coder.<\/p>\n\n\n\n<p>Java 8 ist mittlerweile einige Tage verf\u00fcgbar, aber dennoch m\u00f6chten wir heute auf ein darin enthaltenes Feature schauen, welches wir (und vielleicht auch ihr) bisher selten genutzt haben (habt).<\/p>\n\n\n\n<p>Arbeitet ihr auch gerne mit Methoden, die ggf. Null zur\u00fcckgeben, wenn z.B. ein gesuchtes Element nicht gefunden wurde oder die Operation unvollst\u00e4ndig beendet wurde? Also ich finde es immer wieder umst\u00e4ndlich und unsch\u00f6n explizit auf Null zu pr\u00fcfen bevor ich meine gew\u00fcnschte Verarbeitung auf dem R\u00fcckgabewert durchf\u00fchre.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Null-Pr\u00fcfung am Beispiel<\/h1>\n\n\n\n<p>F\u00fcr diesen Artikel schauen wir uns das Priority-Queue Kata<sup>[1][2]<\/sup> an. Dabei soll eine Priorit\u00e4ten-Warteschlange implementiert werden. Wie soll die Methode <em>dequeue()<\/em>, welche das erste Element der Warteschlange zur\u00fcck gibt, reagieren, wenn noch keine Elemente enthalten sind? Hier sind spontan zwei Verhaltensweisen m\u00f6glich: das Werfen einer Ausnahme oder R\u00fcckgabe von Null.<\/p>\n\n\n\n<p>Angenommen, unsere interne Datrenstruktur der Klasse PriorityQueue&lt;T&gt; ist eine ArrayList mit einem Paar aus dem tats\u00e4chlichen Element und der Priorit\u00e4t.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:java decode:true\">public class PriorityQueue&lt;T&gt; {\n\n    protected ArrayList&lt;Pair&lt;T, Integer&gt;&gt; queue = new ArrayList&lt;&gt;();\n\n    public void enqueue(@NotNull T element, int priority) {...}\n   \n    public T dequeue() {\n        if (queue.size() == 0) {\n            return null;\n        }\n\n        Pair&lt;T, Integer&gt; firstElement = queue.get(0);\n        queue.remove(firstElement);\n        return firstElement.getKey();\n    }\n\n    public int size() {\n        return queue.size();\n    }\n\n}<\/pre>\n\n\n\n<p>Ist die L\u00e4nge der Warteschlange bisher gleich 0 (also leer), dann geben wir Null zur\u00fcck. Sonst holen wir das erste Element und geben den Wert zur\u00fcck, welche in unserem Fall der Schl\u00fcssel des Paars ist.<\/p>\n\n\n\n<p>Die Verwendung der Klasse <em>PriorityQueue<\/em> k\u00f6nnte nun so aussehen:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:java decode:true\">public class Main {\n    public static void main(String[] args) {\n        PriorityQueue&lt;Integer&gt; queue = new PriorityQueue&lt;&gt;();\n        Integer element = queue.dequeue();\n\n        if (element == null) {\n            System.out.println(\"No element.\");\n        } else {\n            System.out.println(element);\n        }\n    }\n}<\/pre>\n\n\n\n<p>Dies soll nat\u00fcrlich nur verdeutlichen, dass Null als m\u00f6glicher R\u00fcckgabewert grunds\u00e4tzlich gesondert behandelt werden muss. Offensichtlich bl\u00e4ht die Null-Abfrage unseren Code auf in nimmt f\u00fcnf Zeilen in Anspruch. Wie sieht die Alternative aus?<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Optional mit Java 8<\/h1>\n\n\n\n<p>Die Klasse <em>Optional<\/em> im Paket <em>java.util<\/em> ist ein Wrapper, also ein Container, der jede andere Klasse einh\u00fcllen kann. Anschlie\u00dfend kann ich den Container fragen, ob diese ein Element enth\u00e4lt und damit arbeiten. Oder, falls der Container leer ist, entsprechend darauf reagieren &#8211; und das alles sehr kompakt.<\/p>\n\n\n\n<p>\u00c4ndern wir unsere Methode <em>dequeue()<\/em> so ab, dass der R\u00fcckgabewert in den Optional-Container geh\u00fcllt wird.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:java decode:true\">public Optional&lt;T&gt; dequeue() {\n    Optional&lt;T&gt; firstValue = Optional.empty();\n\n    if (queue.size() &gt; 0) {\n        Pair&lt;T, Integer&gt; firstElement = queue.get(0);\n        queue.remove(firstElement);\n        firstValue = Optional.of(firstElement.getKey());\n    }\n\n    return firstValue;\n}<\/pre>\n\n\n\n<p>Der R\u00fcckgabewert ist nun von T ge\u00e4ndert in Optional&lt;T&gt;. Damit ist unser Container typisiert. Die Idee ist, einen leeren Container zur\u00fcck zu geben, wenn unsere Warteschlange noch keine Elemente enth\u00e4lt. Was wir damit erreichen und machen k\u00f6nnen, sehen wir weiter unten.<\/p>\n\n\n\n<p>Ein leerer Container wird mit <em>Optional.empty()<\/em> erzeugt. Ist die L\u00e4nge der Warteschlange gr\u00f6\u00dfer 0, so entnehmen wir das erste Element und erzeugen einen Container mit dem Wert dieses Elements. Hier haben wir zwei M\u00f6glichkeiten, Objekte in einen Container einzuh\u00fcllen.<\/p>\n\n\n\n<ol><li><em>Optional.of(T value)<\/em> &#8211; hier ist wichtig, dass unser Objekt nicht Null ist, sonst gibt es eine NullPointerException<\/li><li><em>Optional.ofNullable(T value)<\/em> &#8211; hier d\u00fcrfen wir auch ein Null-Objekt in den Container legen<\/li><\/ol>\n\n\n\n<p>Dann geben wir den Container zur\u00fcck, der entweder leer ist oder den Wert unseres ersten Elements der Warteschlange enth\u00e4lt.<\/p>\n\n\n\n<p>Das Arbeiten mit dem R\u00fcckgabewert unserer Methode kann nun Dank des Containers deutlich vereinfacht werden.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:java decode:true\">public class Main {\n    public static void main(String[] args) {\n        PriorityQueue&lt;Integer&gt; queue = new PriorityQueue&lt;&gt;();\n        Integer element = queue.dequeue();\n\n        if (!queue.dequeue().isPresent()) {\n            System.out.println(\"No element.\");\n        } else {\n            System.out.println(element);\n        }\n    }\n}\n<\/pre>\n\n\n\n<p>Wir fragen den Container einfach, ob es ein Nicht-Null-Objekt enth\u00e4lt. Einfach, oder? Aber&#8230;ist das nun viel k\u00fcrzer als vorher? Das geht noch besser!<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:java decode:true\">public class Main {\n    public static void main(String[] args) {\n        PriorityQueue&lt;Integer&gt; queue = new PriorityQueue&lt;&gt;();\n        queue.dequeue.ifPresent(System.out::println);\n    }\n}\n<\/pre>\n\n\n\n<p>Ahhh, das ist kurz &#8211; aber was macht es? Die Methode <em>ifPresent<\/em> pr\u00fcft, ob ein Nicht-Null-Objekt im Container enthalten ist und f\u00fchrt dann den angegeben Methodenaufruf aus, in diesem Fall wird von <em>System.out<\/em> die Methoden <em>println<\/em> aufgerufen (zur Schreibweise siehe auch Methodenreferenz). Damit wird, falls vorhanden, unser erstes Element ausgegeben. Andernfalls geschieht nichts.<\/p>\n\n\n\n<p>Wollen wir das Objekt aus dem Container abrufen und sind uns sicher, dass der Container nicht Null enth\u00e4lt, ist dies in dieser Form m\u00f6glich.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:java decode:true\">int result = queue.dequeue().get();<\/pre>\n\n\n\n<p>Enth\u00e4lt der Container jedoch Null, wird beim Aufruf der Methode <em>get()<\/em> eine <em>NoSuchElementException<\/em> geworfen. Dies kann durch eine vorhergehende Pr\u00fcfung per <em>isPresent()<\/em> abgesichert werden, da hierbei <em>true<\/em> zur\u00fcckgegeben wird, falls Nicht-Null enthalten ist und <em>false<\/em> andernfalls.<\/p>\n\n\n\n<p>Immer wieder gibt es die Notwendigkeit, das Objekt selbst oder ein Default-Objekt zur\u00fcck zu geben. Dies sieht mit Optional so aus:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:java decode:true\">int result = queue.dequeue().orElse(5);<\/pre>\n\n\n\n<p>Wenn ein Objekt ungleich Null enthalten ist, wird dieses zur\u00fcck gegeben, andernfalls der angegebene Default, in diesem Fall 5.<\/p>\n\n\n\n<p>Soll statt der R\u00fcckgabe des Defaults eine Ausnahme geworfen werfen, ist auch das m\u00f6glich.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted lang:java decode:true\">int result = queue.dequeue().orElseThrow(NullPointerException::new);<\/pre>\n\n\n\n<p>Hier wird, falls von der Methode <em>dequeue() Null<\/em> zur\u00fcck gegeben wird, eine <em>NullPointerException<\/em> geworfen.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Unsere Erfahrungen mit Optional<\/h1>\n\n\n\n<p>Wie bereits erw\u00e4hnt haben wir bisher eher selten Optional verwendet. Allerdings ist dies unserer Ansicht nach eine m\u00e4chtige Erweiterung von Java mit der unser Code an einigen Stellen aufger\u00e4umt werden kann. Ggf. werden wir besonders sch\u00f6ne Anwendungsf\u00e4lle mit Optional nachtr\u00e4glich noch erg\u00e4nzen.<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Zusammenfassung<\/h1>\n\n\n\n<p>Optional in Java 8 ist eine schicke Erweiterung f\u00fcr den Umgang mit Null. L\u00e4stige If-Statements zur Pr\u00fcfung auf Null vor dem Zugriff auf das jeweilige Objekt k\u00f6nnen damit elegant und lesbar verpackt werden. Sicherlich sollte Optional nicht einfach \u00fcberall verwendet werden. Insbesondere bei R\u00fcckgabewerten von Methoden kann dies jedoch hilfreich sein.<\/p>\n\n\n\n<p>Viel Spa\u00df beim Ausprobieren.<\/p>\n\n\n\n<p>Eure Spa\u00df-Coder<\/p>\n\n\n\n<p>Links zum Thema:<\/p>\n\n\n\n<ul><li id=\"gs_cit0\" class=\"gs_citr\" tabindex=\"0\">Kata Priority Queue, http:\/\/ccd-school.de\/coding-dojo\/#cd3<\/li><li class=\"gs_citr\" tabindex=\"0\">Queue als Datenstruktur, https:\/\/de.wikipedia.org\/wiki\/Warteschlange_%28Datenstruktur%29<\/li><li class=\"gs_citr\" tabindex=\"0\">Java-Doc von Optional, https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/util\/Optional.html<\/li><\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Hallo Spa\u00df-Coder. Java 8 ist mittlerweile einige Tage verf\u00fcgbar, aber dennoch m\u00f6chten wir heute auf ein darin enthaltenes Feature schauen, welches wir (und vielleicht auch ihr) bisher selten genutzt haben (habt). Arbeitet ihr auch gerne mit Methoden, die ggf. Null zur\u00fcckgeben, wenn z.B. ein gesuchtes Element nicht gefunden wurde oder die Operation unvollst\u00e4ndig beendet wurde? [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":820,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[1,90],"tags":[],"_links":{"self":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/809"}],"collection":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/comments?post=809"}],"version-history":[{"count":14,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/809\/revisions"}],"predecessor-version":[{"id":1282,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/posts\/809\/revisions\/1282"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media\/820"}],"wp:attachment":[{"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/media?parent=809"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/categories?post=809"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/invidit.de\/blog\/wp-json\/wp\/v2\/tags?post=809"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}