Rheinwerk Computing < openbook >


 
Inhaltsverzeichnis
Materialien
Vorwort
1 Java ist auch eine Sprache
2 Imperative Sprachkonzepte
3 Klassen und Objekte
4 Arrays und ihre Anwendungen
5 Der Umgang mit Zeichenketten
6 Eigene Klassen schreiben
7 Objektorientierte Beziehungsfragen
8 Ausnahmen müssen sein
9 Geschachtelte Typen
10 Besondere Typen der Java SE
11 Generics<T>
12 Lambda-Ausdrücke und funktionale Programmierung
13 Architektur, Design und angewandte Objektorientierung
14 Java Platform Module System
15 Die Klassenbibliothek
16 Einführung in die nebenläufige Programmierung
17 Einführung in Datenstrukturen und Algorithmen
18 Einführung in grafische Oberflächen
19 Einführung in Dateien und Datenströme
20 Einführung ins Datenbankmanagement mit JDBC
21 Bits und Bytes, Mathematisches und Geld
22 Testen mit JUnit
23 Die Werkzeuge des JDK
A Java SE-Module und Paketübersicht
Stichwortverzeichnis


Download:

- Listings, ca. 2,7 MB


Buch bestellen
Ihre Meinung?



Spacer
<< zurück
Java ist auch eine Insel von Christian Ullenboom

Einführung, Ausbildung, Praxis
Buch: Java ist auch eine Insel


Java ist auch eine Insel

Pfeil 12 Lambda-Ausdrücke und funktionale Programmierung
Pfeil 12.1 Funktionale Schnittstellen und Lambda-Ausdrücke
Pfeil 12.1.1 Klassen implementieren Schnittstellen
Pfeil 12.1.2 Lambda-Ausdrücke implementieren Schnittstellen
Pfeil 12.1.3 Funktionale Schnittstellen
Pfeil 12.1.4 Der Typ eines Lambda-Ausdrucks ergibt sich durch den Zieltyp
Pfeil 12.1.5 Annotation @FunctionalInterface
Pfeil 12.1.6 Syntax für Lambda-Ausdrücke
Pfeil 12.1.7 Die Umgebung der Lambda-Ausdrücke und Variablenzugriffe
Pfeil 12.1.8 Ausnahmen in Lambda-Ausdrücken
Pfeil 12.1.9 Klassen mit einer abstrakten Methode als funktionale Schnittstelle? *
Pfeil 12.2 Methodenreferenz
Pfeil 12.2.1 Motivation
Pfeil 12.2.2 Methodenreferenzen mit ::
Pfeil 12.2.3 Varianten von Methodenreferenzen
Pfeil 12.3 Konstruktorreferenz
Pfeil 12.3.1 Parameterlose und parametrisierte Konstruktoren
Pfeil 12.3.2 Nützliche vordefinierte Schnittstellen für Konstruktorreferenzen
Pfeil 12.4 Funktionale Programmierung
Pfeil 12.4.1 Code = Daten
Pfeil 12.4.2 Programmierparadigmen: imperativ oder deklarativ
Pfeil 12.4.3 Das Wesen der funktionalen Programmierung
Pfeil 12.4.4 Funktionale Programmierung und funktionale Programmiersprachen
Pfeil 12.4.5 Funktionen höherer Ordnung am Beispiel von Comparator
Pfeil 12.4.6 Lambda-Ausdrücke als Abbildungen bzw. Funktionen betrachten
Pfeil 12.5 Funktionale Schnittstellen aus dem java.util.function-Paket
Pfeil 12.5.1 Blöcke mit Code und die funktionale Schnittstelle Consumer
Pfeil 12.5.2 Supplier
Pfeil 12.5.3 Prädikate und java.util.function.Predicate
Pfeil 12.5.4 Funktionen über die funktionale Schnittstelle java.util.function.Function
Pfeil 12.5.5 Ein bisschen Bi …
Pfeil 12.5.6 Funktionale Schnittstellen mit Primitiven
Pfeil 12.6 Optional ist keine Nullnummer
Pfeil 12.6.1 Einsatz von null
Pfeil 12.6.2 Der Optional-Typ
Pfeil 12.6.3 Primitive optionale Typen
Pfeil 12.6.4 Erst mal funktional mit Optional
Pfeil 12.6.5 Primitiv-Optionales mit speziellen OptionalXXX-Klassen
Pfeil 12.7 Was ist jetzt so funktional?
Pfeil 12.8 Zum Weiterlesen
 

Zum Seitenanfang

12.3    Konstruktorreferenz Zur vorigen ÜberschriftZur nächsten Überschrift

Um ein Objekt aufzubauen, nutzen wir das Schlüsselwort new. Das führt zum Aufruf eines Konstruktors, dem sich optional Argumente übergeben lassen. Die Java-API deklariert aber auch Typen, von denen sich keine direkten Exemplare mit new aufbauen lassen. Stattdessen gibt es Erzeuger, deren Aufgabe es ist, Objekte aufzubauen. Die Erzeuger können statische oder auch nichtstatische Methoden sein:

Konstruktor …

… erzeugt:

Erzeuger …

… baut:

new Integer( "1" )

Integer

Integer.valueOf( "1" )

Integer

new File( "dir" )

File

Paths.get( "dir" )

Path

new BigInteger( val )

BigInteger

BigInteger.valueOf( val )

BigInteger

Tabelle 12.7    Beispiele für Konstruktoren und Erzeugermethoden

Beide, Konstruktoren und Erzeuger, lassen sich als spezielle Funktionen betrachten, die von einem Typ in einen anderen Typ konvertieren. Damit eignen sie sich perfekt für Transformationen, und in einem Beispiel haben wir das schon eingesetzt:

Arrays.stream( words )

. ...

.map( Integer::parseInt )

. ...

Integer.parseInt(string) ist eine Methode, die sich einfach mit einer Methodenreferenz fassen lässt, und zwar als Integer::parseInt. Aber was ist mit Konstruktoren? Auch sie transformieren! Statt Integer.parseInt(string) hätte ja auch new Integer(string) eingesetzt werden können.

Wo Methodenreferenzen statische Methoden und Objektmethoden angeben können, bieten Konstruktorreferenzen die Möglichkeit, Konstruktoren anzugeben, sodass diese als Erzeuger an anderer Stelle übergeben werden können. Damit lassen sich elegant Konstruktoren als Erzeuger angeben, und zwar auch von einer Klasse, die nicht über Erzeugermethoden verfügt. Wie auch bei Methodenreferenzen spielt eine funktionale Schnittstelle eine entscheidende Rolle. Doch dieses Mal ist es die Methode der funktionalen Schnittstelle, die mit ihrem Aufruf zum Konstruktoraufruf führt. Wo syntaktisch bei Methodenreferenzen rechts vom Doppelpunkt ein Methodenname steht, ist dies bei Konstruktorreferenzen ein new.[ 223 ](Da new ein Schlüsselwort ist, kann keine Methode so heißen; der Identifizierer ist also sicher. ) Also ergibt sich alternativ zu

      .map( Integer::parseInt )       // Methode Integer.parseInt(String)

in unserem Beispiel das Ergebnis mittels:

      .map( Integer::new )            // Konstruktor Integer(String)

Mit der Konstruktorreferenz gibt es vier Möglichkeiten, funktionale Schnittstellen zu implementieren. Die drei verbleibenden Varianten sind Lambda-Ausdrücke, Methodenreferenzen und klassische Implementierung über eine Klasse.

[zB]  Beispiel

Die funktionale Schnittstelle sei:

interface DateFactory { Date create(); }

Die folgende Konstruktorreferenz bindet den Konstruktor an die Methode create() der funktionalen Schnittstelle:

DateFactory factory = Date::new;

System.out.print( factory.create() ); // zum Beispiel Fri Oct 06 22:34:24 CET 2017

Die letzten beiden Zeilen lassen sich auch so zusammenfassen:

System.out.println( ((DateFactory)Date::new).create() );

Soll nur der parameterlose Konstruktor aufgerufen werden, muss die funktionale Schnittstelle nur eine Methode besitzen, die keinen Parameter besitzt und etwas zurückliefert. Der Rückgabetyp der Methode muss natürlich mit dem Klassentyp zusammenpassen. Das gilt für den Typ DateFactory aus unserem Beispiel. Doch es geht noch etwas generischer, zum Beispiel mit der vorhandenen funktionalen Schnittstelle Supplier, wie wir gleich sehen werden.

In der API finden sich oftmals Parameter vom Typ Class, die als Typangabe dazu verwendet werden, dass über den Constructor der Class mit der Methode newInstance() Exemplare gebildet werden. Der Einsatz von Class lässt sich durch eine funktionale Schnittstelle ersetzen, und Konstruktorreferenzen lassen sich anstelle von Class-Objekten übergeben.

 

Zum Seitenanfang

12.3.1    Parameterlose und parametrisierte Konstruktoren Zur vorigen ÜberschriftZur nächsten Überschrift

Beim parameterlosen Konstruktor hat die Methode nur eine Rückgabe, bei einem parametrisierten Konstruktor muss die Methode der funktionalen Schnittstelle natürlich über eine kompatible Parameterliste verfügen:

Konstruktor

Date()

Date(long t)

Kompatible funktionale Schnittstelle

interface DateFactory {

 Date create();

}

interface DateFactory {

 Date create(long t);

}

Konstruktorreferenz

DateFactory factory =

 Date::new;

DateFactory factory =

 Date::new;

Aufruf

factory.create();

factory.create(1);

Tabelle 12.8    Standard- und parametrisierter Konstruktor mit korrespondierenden funktionalen Schnittstellen

[»]  Hinweis

Kommt die Typ-Inferenz des Compilers an ihre Grenzen, sind zusätzliche Typinformationen gefordert. In diesem Fall werden hinter dem Doppelpunkt in eckigen Klammern weitere Angaben gemacht, etwa Klasse::<Typ1, Typ2>new.

 

Zum Seitenanfang

12.3.2    Nützliche vordefinierte Schnittstellen für Konstruktorreferenzen Zur vorigen ÜberschriftZur nächsten Überschrift

Die für einen parameterlosen Konstruktor passende funktionale Schnittstelle muss eine Rückgabe besitzen und keinen Parameter annehmen; die funktionale Schnittstelle für einen parametrisierten Konstruktor muss eine entsprechende Parameterliste haben. Es kommt nun häufig vor, dass der Konstruktor ein parameterloser ist oder genau einen Parameter annimmt. Hier ist es vorteilhaft, dass für diese beiden Fälle die Java-API zwei praktische (generisch deklarierte) funktionale Schnittstellen mitbringt:

Funktionale

Schnittstelle

Funktions-

deskriptor

Abbildung

Passt auf

Supplier<T>

T get()

() → T

parameterlosen Konstruktor

Function<T,R>

R apply(T t)

(T) → R

einfachen parametrisierten Konstruktor

Tabelle 12.9    Vorhandene funktionale Schnittstellen als Erzeuger

[zB]  Beispiel

Die funktionale Schnittstelle Supplier<T> hat eine T get()-Methode, die wir mit dem parameterlosen Konstruktor von Date verbinden können:

Supplier<Date> factory = Date::new;

System.out.print( factory.get() );

Wir nutzen Supplier mit dem Typparameter Date, was den parametrisierten Typ Supplier<Date> ergibt, und get() liefert folglich den Typ Date. Der Aufruf factory.get() führt zum Aufruf des Konstruktors.

Ausblick *

Besonders interessant werden die Konstruktorreferenzen mit den neuen Bibliotheksmethoden der Stream-API. Nehmen wir eine Liste vom Typ Zeitstempel an. Der Konstruktor Date(long) nimmt einen solchen Zeitstempel entgegen, und mit einem Date-Objekt können wir Vergleiche vornehmen, etwa ob ein Datum hinter einem anderen Datum liegt. Folgendes Beispiel listet alle Datumswerte auf, die nach dem 1.1.2020 liegen:

Long[] timestamps = { 2432558632L,      // Thu Jan 29 04:42:38 CET 1970

1609455600000L }; // Fri Jan 01 00:00:00 CET 2021

Date givenYear = new GregorianCalendar( 2000, Calendar.JANUARY, 1 ).getTime();

Arrays.stream( timestamps )

.map( Date::new )

.filter( givenYear::before )

.forEach( System.out::println ); // Fri Jan 01 00:00:00 CET 2021

Die Konstruktorreferenz Date::new hilft dabei, das long mit dem Zeitstempel in ein Date-Objekt zu konvertieren.

[»]  Denksportaufgabe

Ein Konstruktor kann als Supplier oder Function gelten. Problematisch sind mal wieder geprüfte Ausnahmen. Der Leser soll überlegen, ob der Konstruktor URI(String str) throws URISyntaxException über URI::new angesprochen werden kann.

 


Ihre Meinung?

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Java ist auch eine Insel Java ist auch eine Insel

Jetzt Buch bestellen


 Buchempfehlungen
Zum Rheinwerk-Shop: Captain CiaoCiao erobert Java

Captain CiaoCiao erobert Java




Zum Rheinwerk-Shop: Java SE 9 Standard-Bibliothek

Java SE 9 Standard-Bibliothek




Zum Rheinwerk-Shop: Algorithmen in Java

Algorithmen in Java




Zum Rheinwerk-Shop: Objektorientierte Programmierung

Objektorientierte Programmierung




 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und in die Schweiz

InfoInfo



 

 


Copyright © Rheinwerk Verlag GmbH 2021

Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.

Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 

[Rheinwerk Computing]



Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de



Cookie-Einstellungen ändern