Herbert Prähofer: Funktionale Programmierung in Java

Herbert Prähofer: Funktionale Programmierung in Java

Herbert Prähofer
Funktionale Programmierung in Java: Eine umfassende Einführung

1. Auflage
Juli 2020, XIX, 321 Seiten, Broschur
dpunkt.verlag
ISBN: 978-3-86490-757-9

Informationen zum Buch im Katalog der Deutschen Nationalbibliothek.



Das Buch beschreibt die seit der Version 8 in der Sprache Java verfügbaren funktionalen Elemente und demonstriert deren Einsatz. Dabei wird auch ständig der breitere Kontext der funktionalen Programmierung, wie er durch andere funktionale Sprachen, wie z.B. Haskell oder Scala festgelegt wird, berücksichtigt. Das Buch dürfte für Entwickler, die nicht nur am Wie, sondern auch am Warum und an dem größeren Kontext der funktionalen Programmierung interessiert sind, eine ganz spannende Lektüre sein.


Inhalt

Kapitel 1: Einleitung

Ein „revolutionäre[r] Wandel in der Art, wie man Programme in Java gestalten kann“ bewertet Herbert Prähofer gleich auf der ersten Seite seines Buches die Einführung funktionaler Programmierelemente in Java, um dann mit einem kurzen historischen und konzeptuellen Abriss der Welt der funktionalen Programmierung fortzufahren. Begriffe wie Lambda-Ausdrücke, Funktionen höherer Ordnung, parametrischer Polymorphismus, algebraische Datentypen, Typinferenz, Pattern Matching und nicht-strikte Auswertung, die den Leser über die folgenden drei hundert Seiten begleiten werden, werden in der Einleitung kurz eingeführt.

Kapitel 2: Sprachliche Grundlagen

Das zweite Kapitel beginnt mit einer Einführung in die in Java 5 eingeführten Generics, deren „tiefes Verständnis […] essentiell“ für die Verwendung der funktionalen Elemente in Java sei (S. 11). Es werden Beispiele für einfachen und beschränkten parametrischen Polymorphismus gezeigt und das Problem der Ko- und Kontravarianz im Zusammenhang mit generischen Typen samt den Wildcards beschrieben.

Default-Methoden, die einerseits bei der Definition funktionaler Interfaces (d.h. Interfaces, die lediglich eine abstrakte Methode haben) und andererseits bei der Wahrung der Abwärtskompatibilität bei gleichzeitiger Erweiterungsmöglichkeit einer Schnittstelle unterstützen, sind die zweite präsentierte Grundlage. Es folgen Lambda-Ausdrücke, funktionale Interfaces und Methodenreferenzen.

Kapitel 3: Programmieren ohne Seiteneffekte

Im dritten Kapitel geht der Autor auf Prinzipien der funktionalen Programmierung ein: reine Funktionen, die Eigenschaft der referenziellen Transparenz (der Rückgabewert ist nicht vom Aufrufkontext abhängig, sondern lediglich vom Wert der Argumente), Ausnahmebehandlung mittels Optional und funktionale Listen, Paare und Tupel. Bei all diesen Elementen geht es um den Wunsch Seiteneffekte zu vermeiden – der Autor zeigt jedoch, dass „eine rein-funktionale Programmierung ohne veränderliche Variablen und ausschließlich mit unveränderlichen Strukturen in Java oft nicht sinnvoll und auch nicht notwendig ist“ (S. 53, eigene kursive Hervorhebung).

Kapitel 4: Programmieren mit Funktionsparametern

Weiter geht es mit möglichen Einsatzszenarien der in Java neu hinzugekommenen funktionalen Elemente: einerseits zeigt Prähofer wie manches anders als herkömmlich gemacht werden kann, andererseits zeigt er, wie durch die Ausdrucksstärke der funktionalen Programmierung manche Sachverhalte allgemeiner ausgedrückt werden können. Einige der konkreten Themen, die im vierten Kapitel besprochen werden, sind: Funktionen höherer Ordnung, Implementierung von Algorithmen, alternative Implementierungen einiger bekannter objektorientierter Entwurfsmuster mittels funktionaler Elemente (z.B. das Strategy-Pattern oder das Visitor-Pattern), Kontrollstrukturen und Bedarfsauswertung.

Kapitel 5: Kombination von Funktionen

Funktionskomposition ist eine der Stärken funktionaler Programmierung – dieser wird das fünfte Kapitel gewidmet. Anhand konkreter Anwendungsszenarien – Kombinator-Parser und Möglichkeiten domänenspezifische Sprachen (DSL) aufzubauen – werden die Möglichkeiten dieses Features aufgezeigt.

Kapitel 6: Funktoren, Monoide und Monaden

Das sechste Kapitel widmet sich mathematischen Strukturen, die eine große Bedeutung in der funktionalen Programmierung haben: Funktoren und Monaden (Konzepte des mathematischen Teilgebiets der Kategorientheorie) und Monoide (eine algebraische Struktur). Teilweise ist dieses Kapitel als Blick über den Java-Tellerrand zu verstehen, sagt doch der Autor schon am Anfang desselben, dass sich diese Strukturen – bis auf Monoide – in ihrer allgemeinen Form nicht mit den Sprachmitteln von Java ausdrücken lassen (S. 123), weswegen Prähofer sich auch bei seinen Ausführungen an der funktionalen Programmiersprache Haskell orientiert. Teilweise ist das Kapitel aber auch als Vorbereitung für die weiteren Kapiteln über Streams und asynchrone Funktionsketten zu verstehen, welche monade Strukturen darstellen (S. 154).

Kapitel 7: Streams

Kapitel sieben behandelt Streams, d.h. „Objekte, die einen Zugriff auf eine Folge von Elementen bereitstellen“ (S. 155) und Kollektoren. Operationen auf Streams können in drei Kategorien unterteilt werden: Erzeugeroperationen, Zwischenoperationen und Terminal-Operationen. Die Beschreibung solcher Operationen zusammen mit der Betrachtung von Anwendungsbeispielen werden von einem Blick hinter die Implementierungskulissen der Streams mittels sogenannter Spliterators abgerundet.

Kapitel 8: Parallele Streams

Eines der Versprechen funktionaler Programmierung ist die leichte Parallelisierbarkeit dank fehlender Seiteneffekte. Dass sich aus dieser Parallelisierbarkeit nicht trivialerweise ein Performancezuwachs erzielen lässt, zeigt der Autor im Kapitel über parallele Streams. Einerseits geht Prähofer der Frage nach, wie Parallelität zu erzielen sei und geht dabei auch kurz auf das in Java 7 eingeführte Fork/Join Framework ein, andererseits geht er der Frage nach, welche Aspekte die Performanz beeinflussen können. Die Ergebnisse seiner Versuche sind im Anhang B des Buches zusammengefasst. Dabei ist zu sehen, dass die Einflussfaktoren vielfältig sind.

Kapitel 9: Asynchrone Funktionsketten

Das sehr kurze neunte Kapitel behandelt die Klasse CompletableFuture und die Möglichkeit der Funktionskomposition, welche diese bietet.

Kapitel 10: Reaktive Streams

Im längsten Kapitel des Buches werden das reaktive Programmierparadigma und die dieses Paradigma implementierende Bibliothek RxJava vorgestellt. Auch wenn man vielleicht im Falle der reaktiven Programmierung nicht auf Anhieb an „funktionale Programmierung in Java“ denken würde, stellt diese „ein funktionales Modell für die Verarbeitung von ereignisorientierten Datenströmen“ dar (S. 227), weswegen dessen Behandlung in einem Buch über funktionale Programmierung in Java sinnvoll erscheint. Unter anderen werden Grundlagen der reaktiven Programmierung (bestehend aus den Typen Observable und Observer), Operationen auf Observables, Aspekte der Nebenläufigkeit, Fehlerbehandlung, Rückstau und Flusskontrolle vorgestellt. Den Abschluss machen Aspekte der Testbarkeit.

Kapitel 11: Testen mit und von Funktionen

Im vorletzten Kapitel des Buches zeigt der Autor wie funktionaler Code getestet werden kann. Dafür präsentiert er kurz die Möglichkeiten Lambda-Ausdrücke mittels JUnit Version 5 zu verwenden und die Bibliothek AssertJ zum Schreiben von sogenannten Fluent Asserions.

Detaillierter geht Prähofer auf QuickCheck, einer ursprünglich für Haskell entwickelten Bibliothek für sogenanntes eigenschaftsbasiertes Testen (property-based testing auf Englisch), das mittlerweile nach vielen anderen Sprachen, inklusive Java, portiert wurde. Beim eigenschaftsbasierten Testen, einer Testmethode für funktionalen Code, wird versucht, durch das Generieren von Eingaben, spezifizierte Aussagen über diesen Code (d.h. dessen Eigenschaften) zu widerlegen.

Kapitel 12: Weiterführende Konzepte

Im letzten Kapitel des Buches Funktionale Programmierung in Java bewertet der Autor die funktionalen Elemente der Programmiersprache Java und erwähnt, welche funktionalen Elemente zukünftig in die Sprache integriert werden könnten. Seine Schlussfolgerung ist, „dass man in Java sehr wohl funktional programmieren“ könne, auch wenn – im Vergleich zu anderen Sprachen – mit Einschränkungen (S. 289).

Diskussion

Als nach jahrelangen Diskussionen, die als Closures-Debatte bekannt sind (vgl. hierzu Klaus Krefts und Angelika Langers Artikel Understanding the closures debate), funktionale Elemente endlich im März 2014 in die Sprache Java Einzug fanden, war es den meisten Entwicklern wahrscheinlich noch nicht bewusst, wie weitreichend die Implikationen der neuen Features sind, handelte es sich dabei nicht nur um ein paar neue Klassen und Methoden, sondern um einen „revolutionären Wandel in der Art, wie man Programme in Java gestalten kann“, wie Herbert Prähofer gleich auf der ersten Seite der Einleitung des Buches Funktionale Programmierung in Java zu recht feststellt.

Dabei ist in meinen Augen genau das der Hauptverdienst seines Buches: es gelingt dem Autor, dem Leser zu zeigen, dass die funktionale Programmierung eine andere Denkweise erfordert, als der objektorientiert denkende Entwickler es gewohnt ist. An vielen Stellen des Buches wird klar, ohne aber dass der Autor das Thema funktionale Programmierung in Java aus den Augen verliert, dass funktionale Programmierung viel mehr bedeutet als das, was in Java angeboten wird. Gleichzeitig wird aber auch klar, dass Java schon jetzt recht viel bietet. Diese Stärke des Buches ist aber gleichzeitig dessen Schwäche: das Niveau und die Ansprüche an den Leser sind relativ hoch. Für Entwickler aber, die nicht nur am Wie, sondern auch am Warum und an dem größeren Kontext der funktionalen Programmierung interessiert sind, dürfte das Buch eine ganz spannende Lektüre sein.

Wäre Funktionale Programmierung in Java 2014 oder 2015 erschienen, hätte diese Rezension mit dem letzten Paragrafen geendet. Da das Buch jedoch im Juli 2020 erschienen ist, mehr als sechs Jahre nach dem Release von Java 8, stellt sich angesichts der weltbildmäßigen Unterschiede zwischen objektorientierter und funktionaler Programmierung unweigerlich die Frage: inwieweit ist die Verwendung der funktionalen Elemente im Java-Mainstream und somit im Code des „normalen“ Entwicklers angekommen? Die Betrachtung dieses Themas hätte gut zum Ausblick des zwölften Kapitels gepasst. Allerdings handelt es sich dabei auch nur um ein „nice-to-have“, weswegen die restlichen Verdienste des Buches dadurch nicht geschmälert werden.


Zum Autor

Herbert Prähofer ist Professor an der Johannes Kepler Universität Linz (JKU) in Österreich. Seine Forschungsschwerpunkte beinhalten unter anderen die Themen Applikationsframeworks, objektorientierte Analyse und Design und objektorientierte und domänenspezifische Sprachen. Er unterrichtet unter anderem funktionale Programmierung in Java und die Sprachen Kotlin und Scala. Prähofer hat mehrere Buchbeiträge geschrieben und ist Autor und Koautor diverser Fachpublikationen.

Quellen: Autorbeschreibung im Buch Funktionale Programmierung in Java und die Profilseite auf der Website der JKU (letzter Zugriff 2.10.2020).


Folgende Bücher könnten Sie ebenfalls interessieren:

Petre Sora

Petre Soras Interessen sind vielfältig und befinden sich an der Schnittstelle zwischen Mensch und Informationstechnologie. Als studierter Psychologe und Software Engineer war er sechs Jahre als Java-Entwickler in mehreren Unternehmen tätig. Mit der Gründung der Rezensionsplattform nososo hat er sich entschieden eigene Wege zu gehen.

Schreibe einen Kommentar