Methodenschnittstellen in Java
Eine Schnittstelle ist – etwas vereinfacht gesagt – eine Klasse, von der aber keine Objekte mit »new« angelegt werden können. Sie enthält nur Methodenköpfe, aber noch keine vollständigen Definitionen der Methoden. Ihren Methoden fehlt der Methodenrumpf, also die Implementation. Solche eine Methode, die nur aus einem Kopf ohne Rumpf besteht, wird auch als eine abstrakte Methode bezeichnet.
Eine Schnittstelle, welche genau eine abstrakte Methode enthält (wie Runnable, Callable, ActionListener, Gegenbeispiel: java.awt.event.MouseListener) nennen wir auch eine Methodenschnittstelle (funktionale Schnittstelle ).
Eine Implementation einer Schnittstelle ist ein Objekt, welches zu allen Methoden der Schnittstelle auch noch Implementationen (als Methodenrümpfe) enthält.
Methodenliterale sind Implementationen von Methodenschnittstellen, sie bestehen im wesentlich aus einem Methodenrumpf.
Eine Methodenschnittstelle legt den Kopf einer Methode fest, ein Methodenliteral den Rumpf.
Wenn man eine Methodenschnittstelle mit einem Methodenliteral zusammenfügt, so erhält man eine vollständig Methode.
Zuweisung an Variable
- Synopsis von »java.lang.Runnable«
public interface Runnable { public void run(); }
Main.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ final java.lang.Runnable r = () -> java.lang.System.out.println( "alpha" );
java.lang.System.out.println( "beta" );
r.run(); }}transcript
beta
alpha- Effektive run-Methode von »r«
public void run(){ java.lang.System.out.println( "alpha" ); }
Beispiele
Wir stellen hier nur eine Auswahl von Methodenschnittstellen vor.
Eine Methodenschnittstelle ist eine Schnittstelle, die – wenn es sonst keine passendere Schnittstelle in einem bestimmten Fall gibt – als Schnittstelle (Typ) eines Methodenausdrucks dient.
Die Methodenschnittstellen im Paket java.util.function wurden extra dafür geschaffen als Methodenschnittstellen verwendet zu werden.
http://docs.oracle.com/javase/8/docs/api/java/util/function/package-summary.html
Lazy Evaluation
Main.java
public final class Main
{public static void evaluateLater( final java.lang.Runnable expression )
{ java.lang.System.out.printf
( "The expression%n'java.lang.System.out.println( \"alpha\" )'%n" +
"has not been evaluated yet.%n%n" );
expression.run(); }public static void main( final java.lang.String[] args )
{ evaluateLater( () -> java.lang.System.out.println( "alpha" ) ); }}transcript
The expression
'java.lang.System.out.println( "alpha" )'
has not been evaluated yet.
alpha
»accept«-Schnittstellen
»java.util.function.Consumer«
Eine Methode mit einem Parameter und ohne Resultat
package java.util.function;
@FunctionalInterface public interface Consumer< P >
{ void accept( P p ); }- Beispiel
java.util.function.Consumer< java.lang.String >consumer = x ->{ java.lang.System.out.println( x ); };
consumer.accept( "abc" );
»java.util.function.BiConsumer< P, P1 >«
Wie Consumer, aber mit zwei Parametern
»get«-Schnittstellen
»java.util.function.Supplier< R >«
Eine Methode, die keine Parameter hat und ein Resultat liefert
wohl nicht erlaubt: Pfeilmethoden können nicht direkt aufgerufen werden (ungetestet), sondern nur über .get() und ähnliche Methoden
( x -> x )( 2 )
Das folgende Beispiel zeigt wie Ausdrücke mit beliebigen Wirkungen und Werten geschrieben und ausgewertet werden können. Der Ausdruck zwischen »return« und »+« hat die Wirkung der Ausgabe von »2« sowie den Wert »3«.
Main.java
public final class Main
{
public static int m()
{ return
( ( java.util.function.Supplier< java.lang.Integer > )
( () ->{ java.lang.System.out.println( 2 ); return 3; } )).get()
+ 7; }public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( m() ); }}- Protokoll
2
10- Tabelle (Fragment)
Schnittstelle Name Muster
java.util.function.Supplier< T > get ()->{ ... return (T)... }
»apply«-Schnittstellen
»java.util.function.Function< P, R >«
Eine Methode, die einen Parameter hat und ein Resultat liefert
- Beispiel
Main.java
public final class Main
{
public static void main( final java.lang.String[] args )
{ java.lang.System.out.println
( ( ( java.util.function.Function
< java.lang.Integer, java.lang.Integer >)x -> x * x )
.apply( 65 )); }}- Protokoll
4225
- Beispiel
java.util.function.Function< java.lang.Long, java.util.Date >f = java.util.Date::new;
- Beispiel
java.util.function.Function< java.lang.String, java.lang.String >m = System::getProperty;
»java.util.function.BiFunction< P, P1, R >«
Eine Methode, die zwei Parameter hat und ein Resultat liefert
- Beispiel
java.util.function.BiFunction< java.lang.String, java.lang.String, java.lang.String >g = (x, y) -> x + y;
java.lang.System.out.println( g.apply( "alpha", "beta" ));
- Beispiel
java.util.function.BiFunction< java.lang.String, java.lang.String, java.lang.String >g = java.lang.System::getProperty;
»test«-Schnittstellen
»java.util.function.Predicate< P >«
Eine Methode, die einen Parameter hat und ein boolean-Resultat liefert
public interface Predicate< T >{ boolean test( T x ); }
- Beispiel
java.util.function.Predicate< java.lang.String >p = x -> x.contains( "t" );
java.lang.System.out.println( p.test( "alpha" ));
»java.util.function.BiPredicate< P, P1 >«
Eine Methode, die zwei Parameter hat und ein boolean-Resultat liefert
(Ein „Biprädikat“ nennt man in der Mathematik eigentlich eine „Relation“.)
- Beispiel
java.util.function.BiPredicate< java.lang.Integer, java.lang.Integer >r =( i, j )-> i < j;
java.lang.System.out.println( r.test( 3, 4 ));
»applyAsInt«-Schnittstellen
»java.util.function.IntFunction< P >«
java.util.function.IntFunction< P > ähnelt java.util.function.Function< P, java.lang.Integer >, jedoch wird die Verwendung einer Hüllklasse vermieden.
- Beispiel
java.util.function.IntFunction< java.lang.String >f = x-> x.length();
java.lang.System.out.println( f.applyAsInt( "abc" ));
- Beispiel
java.util.function.IntFunction< java.lang.String >l = String::length;
Auch für einige andere Schnittstellen und einige andere elementare Typen gibt es solche Schnittstellen, wie beispielsweise »java.util.function.IntSupplier«, die hier nicht alle aufgelistet werden.
- Beispiel
java.util.function.IntSupplier l = "example"::length;
»run«-Schnittstellen
»java.lang.Runnable«
Diese klassische Schnittstellen kann ebenfalls als Methodenschnittstellen verwendet werden. Sie bietet sich besonders für Methoden ohne Parameter und ohne Resultat an, welche auch „Blöcke“ genannt werden.
»call«-Schnittstellen
»java.util.concurrent.Callable< R >«
Diese klassische Schnittstelle ähnelt »java.util.function.Supplier< R >«.
Anmerkungen
nicht erlaubt: Pfeilmethoden können nicht direkt ausgegeben werden
System.out.println( x -> x );
TRG
Main.java
final class Acceptor
implements java.util.function.Consumer< java.lang.String >
{ @java.lang.Override
public void accept( final java.lang.String word )
{ java.lang.System.out.printf( "Tomaten%nRotkohl Gruenkohl%n%s%n", word ); }}public final class Main
{ public static void main( final java.lang.String[] args )
{ java.util.Arrays.asList( "Gurken", "Spinat", "Kohlrabi" ).
forEach( new Acceptor() ); }}- Protokoll
Tomaten
Rotkohl Gruenkohl
Gurken
Tomaten
Rotkohl Gruenkohl
Spinat
Tomaten
Rotkohl Gruenkohl
KohlrabiMain.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.util.Arrays.asList( "Gurken", "Spinat", "Kohlrabi" ).
forEach
( new java.util.function.Consumer< java.lang.String >()
{ @java.lang.Override
public void accept( final java.lang.String word )
{ java.lang.System.out.printf( "Tomaten%nRotkohl Gruenkohl%n%s%n", word ); }} ); }}- Protokoll
Tomaten
Rotkohl Gruenkohl
Gurken
Tomaten
Rotkohl Gruenkohl
Spinat
Tomaten
Rotkohl Gruenkohl
KohlrabiMain.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.util.Arrays.asList( "Gurken", "Spinat", "Kohlrabi" ).
forEach( ( java.lang.String x )->{ java.lang.System.out.printf( "Tomaten%nRotkohl Gruenkohl%n%s%n", x ); }); }}- Protokoll
Tomaten
Rotkohl Gruenkohl
Gurken
Tomaten
Rotkohl Gruenkohl
Spinat
Tomaten
Rotkohl Gruenkohl
KohlrabiMain.java
public final class Main
{ public static void main( final java.lang.String[] args )
{ java.util.Arrays.asList( "Gurken", "Spinat", "Kohlrabi" ).
forEach( x ->{ java.lang.System.out.printf( "Tomaten%nRotkohl Gruenkohl%n%s%n", x ); }); }}- Protokoll
Tomaten
Rotkohl Gruenkohl
Gurken
Tomaten
Rotkohl Gruenkohl
Spinat
Tomaten
Rotkohl Gruenkohl
Kohlrabi