1. Neuerungen in Java 8: Funktionale Programmierung

Mit der Veröffentlichung von Java 8 erhielt die Sprache leistungsstarke Unterstützung für die funktionale Programmierung . Man könnte sogar sagen, dass es die lang erwartete Unterstützung für die funktionale Programmierung erhielt. Das Codieren wurde schneller, obwohl der Code schwieriger zu lesen war 🙂

Bevor Sie die funktionale Programmierung in Java erlernen , empfehlen wir Ihnen, drei Dinge gut zu verstehen:

  1. OOP, Vererbung und Schnittstellen ( Level 1-2 in der Java Core-Quest ).
  2. Standardmethodenimplementierungen in einer Schnittstelle .
  3. Innere und anonyme Klassen .

Die gute Nachricht ist, dass Sie nicht alles wissen müssen, um viele Funktionen der funktionalen Programmierung in Java nutzen zu können. Die schlechte Nachricht ist, dass es schwierig sein wird, genau zu verstehen, wie alles angeordnet ist und wie alles funktioniert, ohne die anonymen inneren Klassen zu kennen.

In den kommenden Lektionen werden wir uns darauf konzentrieren, wie einfach und unkompliziert es ist, die funktionalen Programmierfunktionen von Java zu nutzen, ohne tiefgreifende Kenntnisse über deren Funktionsweise zu haben.

Es dauert Monate, alle Nuancen der funktionalen Programmierung in Java zu verstehen. Sie können in wenigen Stunden lernen, solchen Code zu lesen. Wir empfehlen daher, klein anzufangen. Auch wenn es sich um I/O-Streams handelt.


2. I/O-Streams: Stream-Pipelines

Erinnern Sie sich daran , dass Sie einmal etwas über I/O-Streams gelernt haben: InputStream, OutputStream, usw.?ReaderWriter

Es gab Stream-Klassen, die Daten aus Datenquellen lesen , z. B. FileInputSteam, und es gab Zwischendatenströme, die Daten aus anderen Streams lesen, z. B. InputStreamReaderund BufferedReader.

Diese Streams könnten in Datenverarbeitungspipelines organisiert werden. Zum Beispiel so:

FileInputStream input = new FileInputStream("c:\\readme.txt");
InputStreamReader reader = new InputStreamReader(input);
BufferedReader buff = new BufferedReader(reader);

String text = buff.readLine();

Es ist wichtig zu beachten, dass wir in den ersten Codezeilen lediglich eine Kette von StreamObjekten erstellen. Die Daten haben die Pipeline noch nicht durchlaufen.

Aber sobald wir die buff.readLine()Methode aufrufen, passiert Folgendes:

  1. Das BufferedReaderObjekt ruft die read()Methode für das InputStreamReaderObjekt auf
  2. Das InputStreamReaderObjekt ruft die read()Methode für das FileInputStreamObjekt auf
  3. Das FileInputStreamObjekt beginnt, Daten aus der Datei zu lesen

Mit anderen Worten: Es gibt keine Datenbewegung entlang der Stream-Pipeline, bis wir mit dem Aufrufen von Methoden wie read()oder beginnen readLine(). Durch den bloßen Aufbau der Stream-Pipeline werden keine Daten durch sie geleitet. Die Streams selbst speichern keine Daten. Sie lesen nur von anderen.

Sammlungen und Streams

Ab Java 8 wurde es möglich, einen Stream zum Lesen von Daten aus Sammlungen (und nicht nur aus ihnen) zu erhalten. Aber das ist nicht das Interessanteste. Es wurde tatsächlich möglich, komplexe Ketten von Datenströmen einfach und unkompliziert aufzubauen. Und auf diese Weise konnte der Code, der zuvor 5–10 Zeilen benötigte, nun in 1–2 Zeilen geschrieben werden.

Beispiel für die Suche nach der längsten Zeichenfolge in einer Liste von Zeichenfolgen:

Die längste Zeichenfolge finden
ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");
String max = list.stream().max((s1, s2)-> s1.length()-s2.length()).get();
ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");
Stream<String> stream = list.stream();
Optional<String> optional = stream.max((s1, s2)-> s1.length()-s2.length());
String max = optional.get();

3. StreamSchnittstelle

Die erweiterte Unterstützung von Java 8 für Streams wird über die Stream<T>Schnittstelle implementiert, wobei Tes sich um einen Typparameter handelt, der den Typ der im Stream übergebenen Daten angibt. Mit anderen Worten: Ein Stream ist völlig unabhängig von der Art der Daten, die er weiterleitet.

Um ein Stream-Objekt aus einer Sammlung abzurufen , rufen Sie einfach dessen stream()Methode auf. Der Code sieht ungefähr so ​​aus:

Stream<Type> name = collection.stream();
Einen Stream aus einer Sammlung abrufen

In diesem Fall wird die Sammlung als Datenquelle des Streams betrachtet und das Stream<Type>Objekt ist ein Werkzeug zum Abrufen von Daten aus der Sammlung in Form eines Datenstroms.

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "Hello", "how's", "life?");
Stream<String> stream = list.stream();

Übrigens können Sie einen Stream nicht nur aus Sammlungen, sondern auch aus Arrays abrufen . Dazu müssen Sie die Methode verwenden. Zum Beispiel:Arrays.stream()

Stream<Type> name = Arrays.stream(array);
Einen Stream aus einem Array abrufen

In diesem Fall wird das Array als Datenquelle für den Stream mit dem Namen betrachtet name.

Integer[] array = {1, 2, 3};
Stream<Integer> stream = Arrays.stream(array);

Stream<Type>Beim Erstellen des Objekts werden keine Daten verschoben . Wir haben einfach ein Stream-Objekt erhalten, um mit dem Aufbau einer Stream-Pipeline zu beginnen.