Java 8 – Optionals

Optionals ist eine mit Java 8 eingeführte Wrapper-Klasse. Ein generischer Containertyp, der genau eine Variable von beliebigem Typ aufnimmt und für die Abfrage, die Initialisierung oder den Status Methoden zur Verfügung stellt, um mit dem enthaltenen – oder eben auch nicht enthaltenen – ‚Wert‘ einer Variablen umzugehen. Und wie geht ein Optional mit dieser Unklarheit um? Es zwingt den Aufrufenden (Caller) einer Methode dazu, sich explizit mit der Möglichkeit einen Null-Wert zurückzubekommen. Und wie? Indem es seinen enthaltenen Wert nur durch die Verwendung der mitgelieferten Methoden hergibt, doch dazu am Beispiel mehr.

Hier möchte ich nur kurz auf einige Funktionen eingehen, Beispiele dazu gibt es in dem Codebeispiel im Git-Repository:

  • Optional<T>.of(<T>) –> erstellt ein Optional mit dem angegebenen Wert, der nicht null sein darf
  • Optional<T>.ofNullable() –> erstellt ein Optional, wobei der angegebene Wert null sein darf
  • Optional<T>.get() –>gibt den Wert zurück, kann zu einer NullPointerException führen
  • Optional<T>.orElse(<T>) –> wenn der Wert nicht vorhanden ist, gibt es den Methodenparameter zurück
  • Optional<T>.orElseThrow(() -> new Exception()) –> ist ein Wert nicht vorhanden, kann mit einer Supplierfunktion eine Exception geworfen werden
  • Optional<T>.ifPresent(Consumer<T>) –> Wenn ein Wert vorhanden ist, wird der Consumer ausgeführt, sonst nicht
  • Optional<T>.isPresent –> liefert einen boolschen Wert zurück, der angibt, ob ein Wert vorhanden ist oder nicht
  • Optional<T>.map() –> Anwendung der angegebenen Funktion auf den Wert, wenn er angegeben ist
  • Optional<T>.filter().ifPresent(Consumer<T>) –> Filter den Wert eines Optionals und wendet anschließend, sofern der Wert noch vorhanden ist, auf das Optional eine Funktion an

Optionals sind value-based classes, die Werte sind also implizit immutable und final.

Java 8 – Stream API

Kommen wir nun im dritten Artikel zu den etwas spannenderen und vielleicht nicht ganz so theoretischen und ersten Annäherungen, die Java8 (oder 1.8) an Neuheiten mit sich bringt – die Stream API.

Das Beispiel aus dem Artikel zu Functional Interfaces wird hierbei als Grundlage verwendet ist aber natürlich als eigenes Package java_8_class_3 im Github-Repository zu finden. Kurz zusammengefasst wird hier die neue forEach-Methode des Iterable Interfaces genutzt, um über alle Elemente der Liste zu iterieren. Statt direkt auf der Liste zu iterieren, werden wir uns im ersten Schritt einen Stream erzeugen und diesen ausgeben:

Auch wenn uns der Optimizer darauf hinweist, dass wir den Ausdruck durch Verwendung der Collections.forEach-Methode vereinfachen können, ist unser Code lauffähig und erzeugt für diese Anweisung folgende Ausgabe:

Dass dieses Beispiel nicht sinnvoll ist – klar und dass die Verwendung von Stream hier nicht notwendig ist, ist auch klar, aber werfen wir einen Blick auf folgendes Beispiel:

Folgende Ausgabe erscheint:

Wir filtern also alle Strings, deren Werte kleiner als 4 sind. Nur der Vollständigkeit halber, können wir dieses Statement auch so schreiben:

Das ganze ist nicht nur deutlich unübersichtlicher und länger, sondern ist auch in der eigentlichen Entwicklung deutlich unangenehmer.

Um den Umgang mit der Stream API zu beherrschen sollten einige Dinge bekannt sein, ohne die es wenig Spaß macht, diese zu verwenden. Beginnen wir mit drei verschiedenen Operationskategorien, die auf Streams angewendet werden können:

  1. Create-Operationen:
    • meineListe.stream() –> sequentiell verarbeiteter Stream auf Basis einer Collection
    • meineListe.parallelStream() –> parallel verarbeiteter Stream auf Basis einerCollection
    • Arrays.stream(meinArray)[.parallel()] –> sequentiell oder parallel verarbeiteter Stream auf Basis eines Arrays
    • Stream.of(String-values oder Integer-values) –> Direkte Erstellung auf Basis von übergebenen Werten
    • IntStream.range(beginInt,endInt) –>Erzeugung eines IntStream mit Range von 7 bis 42, wobei das untere Ende des Intervals enthalten und die obere Grenze nicht enthalten ist
    • Stream<Path> kann durch die die Verwendung von Files.list() auf einem Verzeichnis etabliert werden
    • Files.lines() liest einen Stream<String> Textdatei
  2. Intermediate-Operationen:
    • filter() –> Aussortieren von Elementen auf dem Stream; Verwendung von .filter().filter() ist genauso möglich wie die Verwendung von .filter( (Bedingung).and(Bedingung))
    • distinct() –> Entfernung doppelter Einträge
    • sorted() –> Sortierung
    • skip(n) –> Überspringen der ersten n Elemente
    • limit(n) –> Begrenzung auf n Elemente
    • map() –> Mapping eines bestimmten Element(Typs) zu einem anderen Element(Typ); die Typumwandlung ist hierbei optional, wird aber sehr häufig genutzt
    • peek() –> Untersuchung des aktuellen Elements ohne ein Fortsetzen der Iteration
  3. Terminal-Operationen:
    • forEach() –> Behandlung jedes Elements des Stream
    • collect(Collectors.toList()) –> Alle Elemente des verarbeiteten Streams werden in eine Liste gespeichert
    • collect(Collectors.toMap(myElem::id,myElem::name)) –> Speicherung der aus dem Stream resultierenden Daten in eine Map<Integer,String)
    • collect(Collectors.groupingBy()) –> Gruppierung der Elemente
    • reduce() –> Reduzierung auf einen einzelnen Wert anhand des gegebenen Ausdrucks
    • anyMatch() –> Reduzierung auf einen boolschen Wert anhand des gegeben Predicates
    • findFirst() –> Reduzierung auf das erste Element gekapselt in einem Optional

Es gibt sehr viel mehr Beispiele als die, die hier aufgelistet sind. Gerade im Bereich der Collectors ist noch sehr viel Redebedarf ;-). Eine weitere wichtige Information ist, dass Streams lazy sind, das bedeutet, dass erst mit dem Hinzufügen einer Terminal-Operation die angegebenen Operationen auf einem Stream ausgeführt werden.

ZeroTurnaround hat einen brauchbaren Cheatsheet für den Einstieg veröffentlicht.

Java 8 – Lambdas (Closures)

Während in Java häufig nur von Lambdas gesprochen wird, handelt es sich bei Lambdas um die in Java umgesetzte Variante von Closures, deswegen sollten wir hier einen kurzen Blick auf Closures werfen.

Was ist eine Closure? Eine Closure – ja das Wort ist feminin – ist ein Konstrukt aus der Softwareentwicklung, bei der eine Funktion Zugriff auf seinen Erstellungskontext hat – hää wie jetzt? Na gut, etwas mehr Info anhand eines Beispiels (Quelle des Beispielcodes):

In dem Beispiel (zum Github-Repository) gibt es eine Funktion make_fun(), diese hat als Rückgabe eine anonyme Funktion, hierfür ist Lambda ein Synonym, häufig fällt in diesem Kontext gerade bei JavaScript und PHP der Begriff des Callbacks. Wie zu sehen ist, kann die zurückgegebene Funktion (der Teil in den geschweiften Klammern) auf die lokale Variable n zugreifen und diese sogar verändern, obwohl sie außerhalb des eigentlichen Funktionskontextes liegt, dem sogenannten Erstellungskontext. Die Funktion make_fun hat in der Methodensignatur keinen Funktionsparameter und einen Rückgabewert vom Typ Function<Integer, Integer>, was zugegeben auch zu erwarten war, da wir eine anonyme Funktion erstellen. Ein Blick hinter die Kulissen des Typs zeigt:

Wobei T der Typ des Parameters für die Funktion und R der Typ des Rückgabewertes der Funktion ist. Die Schreibweise ist etwas gewöhnungsbedürftig für Neulinge im Feld der funktionalen Programmierung, aber nach kurzer Eingewöhnungsphase doch verständlich. Die Invocation unserer Funktion findet anschließend durch den Aufruf der apply-Methode statt. Hierbei wird die Methode auf die übergebenen Werte angewendet – beispielhaft mit 5 Werten in zwei Durchläufen.

Zu sehen ist, dass sowohl der Callback auf der Variablen x als auch auf der Variablen y ihre eigene Variable n haben (wovon wir auch ausgegangen sind), sich der Inhalt der Variablen aber nicht ändert. Sollte nun versucht werden, den Wert von n innerhalb des Callbacks zu verändern, beispielsweise durch n += arg;, so wirft der Compiler (JIT Compiler) direkt einen Fehler:

Das bedeutet, dass die in Java verfügbaren Closures in Form von Lambdas keine Variablen sondern Wert geschlossenen Closures sind (Zur Erinnerung eine Closure ist ein über Speicherstruktur und Funktion geschlossenes Konstrukt).

Wenn eine Variable verändert werden muss, kann dies durch ein auf dem Heap abgelegtes Objekt etabliert werden:

Bringen wir diesen Code nun mit unseren beiden Beispielen zur Ausführung erhalten wir folgendes Ergebnis, in dem wir auch die außerhalb der Funktion gelagerten Variablen bearbeiten können, da der Compiler hier lediglich die Änderung der Referenz innerhalb der Funktion prüft (probiere einfach, myWrapperClass innerhalb der anonymen Methode neu zu instanziieren):

Wenn man hierbei noch Concurrency-Probleme beachtet (mutable shared state), hat man durch einen kleinen Umweg genau das, was ein Closure ausmacht.

Trotzdem sind Lambdas sicherlich eine sehr sinnvolle Neuerung in Java8.

Der Programmcode kann im Github-Repository gecloned werden. Der relevante Beispielcode findet sich im Package java_8_class_2.

Java 8 – Functional Interfaces

Ich bin mir oft nicht sicher, ob der Hype um das Thema funktionale Programmierung übertrieben ist, doch ich habe erlebt, dass einige Operationen kürzer, schneller und übersichtlicher implementiert werden können und beispielsweise mit parallelen Streams auch noch schneller verarbeitet werden können – vorausgesetzt eine parallele Verarbeitung ist möglich. Zudem denke ich, dass kein Entwickler, wirklich um ein grundsätzliches Verständnis der funktionalen Programmierung drum herum kommt, da viele Kunden und Auftraggeber häufig von Buzzwords getrieben sind und der Meinung sind, dass eine moderne Software auf einem funktionalen Programmieransatz beruht – ich sehe dies wie viele meiner Kollegen etwas anders, die sagen…“Kommt drauf an“…

Doch nun genug Stimmungsmache ;-):

Im ersten Code-Snippet werden wir mit Hilfe der neuen default-Implementierung einer forEach-Methode aus dem allgemein bekannten Iterable-Interface:

In dem ersten Beispiel im Kontext Java 8 wird über eine Liste von Strings iteriert und die Char-Sequence ausgegeben. Dazu habe ich hier ein Github-Repository mit den Beispielen angelegt, über die wir hier sprechen werden. Betrachtet wird die Klasse Java_8_Class_1. Bisher verwendeten wir die in Java 1.5 eingeführte extended-Loop:

Das Interface Iterable bringt nun die forEach Methode mit, die als Parameter ein Consumer<T> als Parameter erwartet:

Die Ausgabe von Java_8_Class_1 sollte wie nachfolgend dargestellt sein:

 

Java 7 – try mit AutoClosables, try(Ressource res), Type Inference

Die erste Frage, die ich mir heute morgen gestellt habe, wie komme ich drauf, dass ich Ende 2015 Beiträge über Java 7 veröffentliche…naja ich komme jetzt gerade erst dazu, mich damit zu beschäftigen, leider…

AutoCloseable – ein Interface, das mit Java 7 eingeführt wurde, es fordert die Implementierung einer Methode … schrecklich überraschend … close() … ein. Zudem kann ich nun Ressourcen im Kopf des try-Blocks deklarieren, der Vorteil hier ganz klar; Egal, ob die try-Anweisung vollständig abläuft oder abrupt  endet, die close()-Methode von Ressourcen, die das Interface AutoClosable implementieren werden definitiv aufgerufen. So können Socket, Filehandles oder Reader-Ressourcen automatisch beendet werden, auch dann wenn eine Exception auftritt. Es können zudem mehrere Ressource ; separiert im try instanziiert werden, bspw.:

Hingewiesen sei auf das rot-markierte Semikolon nach der zweiten Ressourcen, dieses ist optional und kann ja nach Belieben gesetzt oder nicht gesetzt werden. Ein weiterer Vorteil ist, dass zur Laufzeit bekannt ist, welche Ressourcen bereits geschlossen worden sind. Das bedeutet, tritt ein Problem bei der Instanziierung von r2 auf, so wird nur r1 automatisch geschlossen, da dies für r2 nicht notwendig ist.

Aber in dem kurzen Codeblock ist noch mehr, das so nicht ganz so einfach mit Java 6 ging. Genau…die Exceptions…ein Pipe-Symbol/logisches ODER…Das ganze nennt sich Exception-Chaining. Wenn wie in diesem Beispiel drei Exceptions die gleiche Art der Behandlung haben, können die Blöcke auf o.g. Weise zusammengefasst werden…auch wieder sehr praktisch.

Zu guter letzt möchte ich noch weiter auf die Optimierungen beim Entwickeln eingehen. Seit Java 7 können in Variablendeklarationen von Generics die typisierenden Argumente beim Konstruktor-Aufruf weggelassen werden, also statt:

Können wir die verkürzte Schreibweise verwenden:

Die Kombination aus den beiden spitzen Klammern ‚<>‘ wird auch als Diamond bezeichnet. Zusammengefasst kann der Diamond den parametrisierten Typ des Konstruktors einer generischen Klasse ersetzen. Das Weglassen des Diamonds ist bei der Instanziierung nicht erlaubt, weil sonst (in diesem Fall) der Raw-Type der Hashmap angenommen und nicht der generische Typ angenommen wird.

Empfohlen wird zudem der Einsatz ausschließlich bei der Instanziierung von Variablen, nicht in Funktionsaufrufen, auch wenn dies theoretisch möglich ist.

Java7 – Neuerung – Danke!

Heute … gestern … und auch der Tag davor – so fühlt es sich zumindest als Java-Entwickler oftmals an, wenn man mal wieder in die Situation kommt, equals() und hashCode()-Methoden in einem Objekt zu implementieren.  So führt der traditionelle Weg am Referenzvergleich, null-Check und am Ende an diversen if() ..elseif()-Checks vorbei. Diese als „verbose“ (langatmige) Implementierung kennt jeder. Etwas schicker geht es mit den ternären Operatoren (zur Erinnerung: ‚wenn ? dann : sonst‘). Obi Ezechukwu hat uns dann mit seinem compactEquals weitergeholfen, als er seine compactEquals()-Methode vorgestellt hat; er fügt die zu vergleichenden Members der zu vergleichenden Objekte einem Array hinzu,  und nutzt Arrays.equals(Object,Object). Ein ähnlich umständliches Verfahren wird bekannterweise auch für der Überschreiben der hashCode()-Methode eingegangen, was ja notwendig ist, wenn die equals()-Methode eines Objekts überschrieben wird.

IDEs wie IntelliJ, Netbeans und Eclipse helfen natürlich bei der automatischen Erstellung der Methoden in altertümlichem Sinne, was den Stil allerdings auch nicht schöner macht.

Mit der Einführung von Java7, können equals() und hashCode() nun recht komfortabel, objektweise erstellt werden.

 

 

Hingewiesen sei hier auch noch auf die deepEquals()-Methode der Objects-Klasse.

 

Quellen: http://docs.oracle.com/javase/7/docs/api/java/util/Objects.html

Apache Wicket – Der Einstieg

Seit nun fast 15 Monaten beschäftige ich mich in meinem Projektumfeld mit Spring und Hibernate. Langsam meldet sich mit Innerstes und schreit nach mehr Input. Andere lernen Sprachen oder versuchen neue Kunststückchen mit ihren Fingern zu vollführen, aber der allgemeine Informatiker…nunja…macht das nicht.

Der Informatiker erweitert sein Repertoire um Technologien und Erfahrungen. Ich habe mir nun Apache Wicket vorgenommen. Bei Wicket kommt mit Wissen zu Java und HTML vollkommen aus. Ich werde versuchen, einige der wichtigsten Fragestellungen, die beim Einarbeiten in dieses Framework auftreten, nieder zu schreiben und natürlich auch zu beantworten.

Nachdem wir das Warum? geklärt haben, kommen wir zu einem schweren Schritt, wie anfangen? O_o

  1. Apache Tomcat 7 mit JDK 7 (bspw. OpenJDK 7) sollte als Grundlage vorhanden sein
  2. Eine brauchbare IDE: https://www.jetbrains.com/idea/ – die meiner Meinung nach beste IDE (Netbeans und Eclipse wurden abgelöst)
  3. Ich empfehle die Verwendung von Maven als Dependency Manager

Okay, sobald wir das alles eingerichtet haben…sind schon gut und gerne mal 60 Minuten vergangen ;-).

Das war die Einrichtung der Entwicklungsumgebung, kommen wir nun zum ersten lauffähigen Projekt mit Wicket. Aber was nun? Na gut, keine Ahnung, besorgen wir uns Hilfe bei Leuten die Apache Wicket entwickeln und uns grandiose Hilfen anbieten. Maven Archtypes…Neues Projekt –> Maven –> **gnampf** Wicket in Version 1.3.2 als Archtype vorhanden…Version 7 ist doch aktuell….gerade gelesen :-/ na gut wicket.apache.org *such* Quickstart –> Boah fett *.*

Hier gibt es einen generierten Befehl, mit dessen Hilfe wir ein Wicketprojekt erstellen können:

Ich habe mal die interessanten Parameter des Befehls in rot markiert, diese können bspw. in IDEA als neuer Archtype angegeben und gespeichert werden. Sobald das Projekt erfolgreich erstellt worden ist, haben wir eine lauffähige WebApplicationentwickelt …. *yey*

Aber was genau ist hier nun passiert? Mit dem MavenArchtype wurde eine POM erzeugt, diese lädt alle Dinge automatisch aus dem angegebenen Repository herunter, wenn dort nicht verfügbar, ggf. auch von anderer Stelle (Dependency Management). Zusätzlich können in der POM Informationen zur Applikation hinterlegt werden, wie Author, Applikationsname oder Verison eurer Applikation. Die Version kann bspw. bei Verwendung von Releasezyklen automatisiert durch einen Jenkins verwaltet werden….doch dazu später mehr….vielleicht ;-).

Also was jetzt? Genau, ein Container in dem die Webapplikation (WebApp) laufen kann, muss her. Oben in den Bedingungen schon gesehen…Tomcat 7.  In der Pom ist auch ein alternativer Servelet-Container als Dependency vorhanden, der natürlich auch problemlos verwendet werden kann:

Es ist wichtig, dass Java 7 verwendet wird, wie es hier auch steht:

 

 

Nach Konfiguration des Tomcat 7 in der IDE sollte einem Start der Applikation nichts mehr im Wege stehen. Bereits nach 453ms öffnet such ein Browserfenster und die „Quickstart“ erscheint.

Glück auf! Später mehr 😉