CodeGym /Java-Blog /Random-DE /Eine Erklärung von Lambda-Ausdrücken in Java. Mit Beispie...
John Squirrels
Level 41
San Francisco

Eine Erklärung von Lambda-Ausdrücken in Java. Mit Beispielen und Aufgaben. Teil 1

Veröffentlicht in der Gruppe Random-DE
Für wen ist dieser Artikel?
  • Es ist für Leute gedacht, die glauben, Java Core bereits gut zu kennen, aber keine Ahnung von Lambda-Ausdrücken in Java haben. Oder vielleicht haben sie etwas über Lambda-Ausdrücke gehört, aber es fehlen die Details
  • Es ist für Leute gedacht, die ein gewisses Verständnis für Lambda-Ausdrücke haben, sich aber dennoch von ihnen einschüchtern lassen und nicht daran gewöhnt sind, sie zu verwenden.
Eine Erklärung von Lambda-Ausdrücken in Java.  Mit Beispielen und Aufgaben.  Teil 1 - 1Wenn Sie nicht in eine dieser Kategorien passen, ist dieser Artikel möglicherweise langweilig, fehlerhaft oder im Allgemeinen nicht Ihr Ding. In diesem Fall können Sie gerne auf andere Dinge eingehen oder, wenn Sie sich in der Materie gut auskennen, gerne in den Kommentaren Vorschläge machen, wie ich den Artikel verbessern oder ergänzen könnte. Das Material erhebt keinen Anspruch auf akademischen Wert, geschweige denn auf Neuheit. Ganz im Gegenteil: Ich werde versuchen, Dinge, die (für manche Menschen) komplex sind, so einfach wie möglich zu beschreiben. Eine Bitte, die Stream-API zu erklären, hat mich dazu inspiriert, dies zu schreiben. Ich habe darüber nachgedacht und bin zu dem Schluss gekommen, dass einige meiner Stream-Beispiele ohne Verständnis für Lambda-Ausdrücke unverständlich wären. Wir beginnen also mit Lambda-Ausdrücken. Was müssen Sie wissen, um diesen Artikel zu verstehen?
  1. Sie sollten objektorientierte Programmierung (OOP) verstehen, nämlich:

    • Klassen, Objekte und der Unterschied zwischen ihnen;
    • Schnittstellen, wie sie sich von Klassen unterscheiden und Beziehung zwischen Schnittstellen und Klassen;
    • Methoden, wie man sie aufruft, abstrakte Methoden (dh Methoden ohne Implementierung), Methodenparameter, Methodenargumente und wie man sie übergibt;
    • Zugriffsmodifikatoren, statische Methoden/Variablen, endgültige Methoden/Variablen;
    • Vererbung von Klassen und Schnittstellen, Mehrfachvererbung von Schnittstellen.
  2. Kenntnisse in Java Core: generische Typen (Generika), Sammlungen (Listen), Threads.
Nun, lasst uns loslegen.

Eine kleine Geschichte

Lambda-Ausdrücke kamen aus der funktionalen Programmierung nach Java und von der Mathematik dorthin. In den Vereinigten Staaten arbeitete Mitte des 20. Jahrhunderts Alonzo Church, der sich sehr für Mathematik und alle Arten von Abstraktionen interessierte, an der Princeton University. Es war Alonzo Church, der die Lambda-Kalküle erfand, bei der es sich ursprünglich um eine Reihe abstrakter Ideen handelte, die keinerlei Bezug zur Programmierung hatten. Mathematiker wie Alan Turing und John von Neumann arbeiteten zur gleichen Zeit an der Princeton University. Alles passte zusammen: Church entwickelte die Lambda-Rechnung. Turing entwickelte seine abstrakte Rechenmaschine, die heute als „Turing-Maschine“ bekannt ist. Und von Neumann schlug eine Computerarchitektur vor, die die Grundlage moderner Computer bildete (heute „von Neumann-Architektur“ genannt). Zu dieser Zeit war die Alonzo-Kirche Seine Ideen wurden nicht so bekannt wie die Werke seiner Kollegen (mit Ausnahme des Gebiets der reinen Mathematik). Wenig später interessierte sich jedoch John McCarthy (ebenfalls Absolvent der Princeton University und zum Zeitpunkt unserer Geschichte Mitarbeiter des Massachusetts Institute of Technology) für Churchs Ideen. Basierend auf diesen Ideen entwickelte er 1958 die erste funktionale Programmiersprache, LISP. Und 58 Jahre später drangen die Ideen der funktionalen Programmierung in Java 8 ein. Es sind noch nicht einmal 70 Jahre vergangen ... Ehrlich gesagt ist es nicht die längste Zeit, die es dauert, bis eine mathematische Idee in die Praxis umgesetzt wird. ein Mitarbeiter des Massachusetts Institute of Technology) interessierte sich für Churchs Ideen. Basierend auf diesen Ideen entwickelte er 1958 die erste funktionale Programmiersprache, LISP. Und 58 Jahre später drangen die Ideen der funktionalen Programmierung in Java 8 ein. Es sind noch nicht einmal 70 Jahre vergangen ... Ehrlich gesagt ist es nicht die längste Zeit, die es dauert, bis eine mathematische Idee in die Praxis umgesetzt wird. ein Mitarbeiter des Massachusetts Institute of Technology) interessierte sich für Churchs Ideen. Basierend auf diesen Ideen entwickelte er 1958 die erste funktionale Programmiersprache, LISP. Und 58 Jahre später drangen die Ideen der funktionalen Programmierung in Java 8 ein. Es sind noch nicht einmal 70 Jahre vergangen ... Ehrlich gesagt ist es nicht die längste Zeit, die es dauert, bis eine mathematische Idee in die Praxis umgesetzt wird.

Der Kern der Sache

Ein Lambda-Ausdruck ist eine Art Funktion. Sie können es sich wie eine gewöhnliche Java-Methode vorstellen, jedoch mit der besonderen Fähigkeit, als Argument an andere Methoden übergeben zu werden. Das ist richtig. Es ist möglich, nicht nur Zahlen, Strings und Cats an Methoden zu übergeben, sondern auch andere Methoden! Wann könnten wir das brauchen? Dies wäre beispielsweise hilfreich, wenn wir eine Rückrufmethode übergeben möchten. Das heißt, wenn wir die von uns aufgerufene Methode benötigen, um die Fähigkeit zu haben, eine andere Methode aufzurufen, die wir an sie übergeben. Mit anderen Worten: Wir haben die Möglichkeit, unter bestimmten Umständen einen Rückruf und unter anderen einen anderen Rückruf weiterzugeben. Und damit unsere Methode, die unsere Rückrufe empfängt, sie aufruft. Sortieren ist ein einfaches Beispiel. Angenommen, wir schreiben einen cleveren Sortieralgorithmus, der so aussieht:

public void mySuperSort() { 
    // We do something here 
    if(compare(obj1, obj2) > 0) 
    // And then we do something here 
}
In der ifAnweisung rufen wir die compare()Methode auf, übergeben zwei zu vergleichende Objekte und wollen wissen, welches dieser Objekte „größer“ ist. Wir gehen davon aus, dass der „größere“ vor dem „kleineren“ kommt. Ich setze „größer“ in Anführungszeichen, weil wir eine universelle Methode schreiben, die nicht nur in aufsteigender, sondern auch in absteigender Reihenfolge sortieren kann (in diesem Fall ist das „größere“ Objekt tatsächlich das „kleinere“ Objekt , und umgekehrt). Um den spezifischen Algorithmus für unsere Sortierung festzulegen, benötigen wir einen Mechanismus, um ihn an unsere mySuperSort()Methode zu übergeben. Auf diese Weise können wir unsere Methode „kontrollieren“, wenn sie aufgerufen wird. Natürlich könnten wir zwei separate Methoden schreiben – mySuperSortAscend()undmySuperSortDescend()— zum Sortieren in aufsteigender und absteigender Reihenfolge. Oder wir könnten der Methode ein Argument übergeben (z. B. eine boolesche Variable; wenn wahr, dann in aufsteigender Reihenfolge sortieren, und wenn falsch, dann in absteigender Reihenfolge). Aber was ist, wenn wir etwas Kompliziertes sortieren möchten, beispielsweise eine Liste von String-Arrays? Woher mySuperSort()weiß unsere Methode, wie diese String-Arrays sortiert werden sollen? Nach Größe? Anhand der Gesamtlänge aller Wörter? Vielleicht alphabetisch basierend auf der ersten Zeichenfolge im Array? Und was ist, wenn wir die Liste der Arrays in einigen Fällen nach der Array-Größe und in anderen Fällen nach der kumulativen Länge aller Wörter in jedem Array sortieren müssen? Ich gehe davon aus, dass Sie bereits von Komparatoren gehört haben und dass wir in diesem Fall einfach ein Komparatorobjekt an unsere Sortiermethode übergeben würden, das den gewünschten Sortieralgorithmus beschreibt. Weil der Standardsort()Die Methode basiert auf dem gleichen Prinzip wie das , das ich in meinen Beispielen mySuperSort()verwenden werde .sort()

String[] array1 = {"Dota", "GTA5", "Halo"}; 
String[] array2 = {"I", "really", "love", "Java"}; 
String[] array3 = {"if", "then", "else"}; 

List<String[]> arrays = new ArrayList<>(); 
arrays.add(array1); 
arrays.add(array2); 
arrays.add(array3); 

Comparator<;String[]> sortByLength = new Comparator<String[]>() { 
    @Override 
    public int compare(String[] o1, String[] o2) { 
        return o1.length - o2.length; 
    } 
}; 

Comparator<String[]> sortByCumulativeWordLength = new Comparator<String[]>() { 

    @Override 
    public int compare(String[] o1, String[] o2) { 
        int length1 = 0; 
        int length2 = 0; 
        for (String s : o1) { 
            length1 += s.length(); 
        } 

        for (String s : o2) { 
            length2 += s.length(); 
        } 

        return length1 - length2; 
    } 
};

arrays.sort(sortByLength);
Ergebnis:

  1. Dota GTA5 Halo
  2. if then else
  3. I really love Java
Hier werden die Arrays nach der Anzahl der Wörter in jedem Array sortiert. Ein Array mit weniger Wörtern wird als „kleiner“ betrachtet. Deshalb steht es an erster Stelle. Ein Array mit mehr Wörtern gilt als „größer“ und wird am Ende platziert. Wenn wir der sort()Methode einen anderen Komparator übergeben, z. B. sortByCumulativeWordLength, erhalten wir ein anderes Ergebnis:

  1. if then else
  2. Dota GTA5 Halo
  3. I really love Java
Jetzt werden die Arrays nach der Gesamtzahl der Buchstaben in den Wörtern des Arrays sortiert. Im ersten Array gibt es 10 Buchstaben, im zweiten 12 und im dritten 15. Wenn wir nur einen einzigen Komparator haben, müssen wir dafür keine separate Variable deklarieren. Stattdessen können wir einfach direkt zum Zeitpunkt des Aufrufs der sort()Methode eine anonyme Klasse erstellen. Etwas wie das:

String[] array1 = {"Dota", "GTA5", "Halo"}; 
String[] array2 = {"I", "really", "love", "Java"}; 
String[] array3 = {"if", "then", "else"}; 

List<String[]> arrays = new ArrayList<>(); 

arrays.add(array1); 
arrays.add(array2); 
arrays.add(array3); 

arrays.sort(new Comparator<String[]>() { 
    @Override 
    public int compare(String[] o1, String[] o2) { 
        return o1.length - o2.length; 
    } 
}); 
Wir erhalten das gleiche Ergebnis wie im ersten Fall. Aufgabe 1. Schreiben Sie dieses Beispiel so um, dass Arrays nicht in aufsteigender Reihenfolge der Anzahl der Wörter in jedem Array, sondern in absteigender Reihenfolge sortiert werden. Das alles wissen wir bereits. Wir wissen, wie man Objekte an Methoden übergibt. Je nachdem, was wir gerade benötigen, können wir unterschiedliche Objekte an eine Methode übergeben, die dann die von uns implementierte Methode aufruft. Das wirft die Frage auf: Warum in aller Welt brauchen wir hier einen Lambda-Ausdruck?  Denn ein Lambda-Ausdruck ist ein Objekt, das genau eine Methode hat. Wie ein „Methodenobjekt“. Eine in einem Objekt verpackte Methode. Es hat lediglich eine etwas ungewohnte Syntax (dazu später mehr). Schauen wir uns diesen Code noch einmal an:

arrays.sort(new Comparator<String[]>() { 
    @Override 
    public int compare(String[] o1, String[] o2) { 
        return o1.length - o2.length; 
    } 
});
Hier nehmen wir unsere Array-Liste und rufen ihre sort()Methode auf, an die wir ein Komparatorobjekt mit einer einzelnen compare()Methode übergeben (der Name spielt für uns keine Rolle – schließlich ist es die einzige Methode dieses Objekts, wir können also nichts falsch machen). Diese Methode hat zwei Parameter, mit denen wir arbeiten werden. Wenn Sie mit IntelliJ IDEA arbeiten, haben Sie wahrscheinlich gesehen, dass es angeboten wird, den Code wie folgt deutlich zu komprimieren:

arrays.sort((o1, o2) -> o1.length - o2.length);
Dadurch werden sechs Zeilen auf eine einzige kurze reduziert. 6 Zeilen werden als eine kurze umgeschrieben. Etwas ist verschwunden, aber ich garantiere, dass es nichts Wichtiges war. Dieser Code funktioniert genauso wie mit einer anonymen Klasse. Aufgabe 2. Versuchen Sie, die Lösung für Aufgabe 1 mithilfe eines Lambda-Ausdrucks umzuschreiben (bitten Sie zumindest IntelliJ IDEA, Ihre anonyme Klasse in einen Lambda-Ausdruck zu konvertieren).

Lassen Sie uns über Schnittstellen sprechen

Im Prinzip ist eine Schnittstelle einfach eine Liste abstrakter Methoden. Wenn wir eine Klasse erstellen, die eine Schnittstelle implementiert, muss unsere Klasse die in der Schnittstelle enthaltenen Methoden implementieren (oder wir müssen die Klasse abstrakt machen). Es gibt Schnittstellen mit vielen verschiedenen Methoden (zum Beispiel  List) und es gibt Schnittstellen mit nur einer Methode (zum Beispiel Comparatoroder Runnable). Es gibt Schnittstellen, die keine einzige Methode haben (sog. Marker-Schnittstellen wie z. B. Serializable). Schnittstellen, die nur eine Methode haben, werden auch funktionale Schnittstellen genannt . In Java 8 sind sie sogar mit einer speziellen Annotation gekennzeichnet:@FunctionalInterface. Es sind diese Ein-Methoden-Schnittstellen, die als Zieltypen für Lambda-Ausdrücke geeignet sind. Wie ich oben sagte, ist ein Lambda-Ausdruck eine in ein Objekt eingeschlossene Methode. Und wenn wir ein solches Objekt übergeben, übergeben wir im Wesentlichen diese einzelne Methode. Es stellt sich heraus, dass es uns egal ist, wie die Methode heißt. Das Einzige, was für uns zählt, sind die Methodenparameter und natürlich der Körper der Methode. Im Wesentlichen ist ein Lambda-Ausdruck die Implementierung einer funktionalen Schnittstelle. Wo immer wir eine Schnittstelle mit einer einzelnen Methode sehen, kann eine anonyme Klasse als Lambda umgeschrieben werden. Wenn die Schnittstelle über mehr oder weniger als eine Methode verfügt, funktioniert ein Lambda-Ausdruck nicht und wir verwenden stattdessen eine anonyme Klasse oder sogar eine Instanz einer gewöhnlichen Klasse. Jetzt ist es an der Zeit, sich ein wenig mit Lambdas zu befassen. :) :)

Syntax

Die allgemeine Syntax sieht etwa so aus:

(parameters) -> {method body}
Das heißt, Klammern um die Methodenparameter, ein „Pfeil“ (gebildet durch einen Bindestrich und ein Größer-als-Zeichen) und dann wie immer der Methodenkörper in geschweiften Klammern. Die Parameter entsprechen denen, die in der Schnittstellenmethode angegeben sind. Wenn Variablentypen vom Compiler eindeutig bestimmt werden können (in unserem Fall weiß er, dass wir mit String-Arrays arbeiten, da unser ListObjekt mit ] typisiert wird String[), müssen Sie deren Typen nicht angeben.
Wenn sie nicht eindeutig sind, geben Sie den Typ an. IDEA färbt es grau, wenn es nicht benötigt wird.
Weitere Informationen finden Sie in diesem Oracle-Tutorial und anderswo. Dies wird als „ Zieltypisierung “ bezeichnet. Sie können die Variablen beliebig benennen – Sie müssen nicht dieselben Namen verwenden, die in der Schnittstelle angegeben sind. Wenn keine Parameter vorhanden sind, geben Sie einfach leere Klammern an. Wenn nur ein Parameter vorhanden ist, geben Sie einfach den Variablennamen ohne Klammern an. Nachdem wir nun die Parameter verstanden haben, ist es an der Zeit, den Hauptteil des Lambda-Ausdrucks zu besprechen. Innerhalb der geschweiften Klammern schreiben Sie Code wie bei einer gewöhnlichen Methode. Wenn Ihr Code aus einer einzigen Zeile besteht, können Sie die geschweiften Klammern ganz weglassen (ähnlich wie bei if-Anweisungen und for-Schleifen). Wenn Ihr einzeiliges Lambda etwas zurückgibt, müssen Sie kein a einschließenreturnStellungnahme. Wenn Sie jedoch geschweifte Klammern verwenden, müssen Sie eine returnAnweisung explizit einschließen, genau wie bei einer gewöhnlichen Methode.

Beispiele

Beispiel 1.

() -> {}
Das einfachste Beispiel. Und das Sinnloseste :), da es nichts bringt. Beispiel 2.

() -> ""
Ein weiteres interessantes Beispiel. Es benötigt nichts und gibt eine leere Zeichenfolge zurück ( returnwird weggelassen, da es unnötig ist). Hier ist das Gleiche, aber mit return:

() -> { 
    return ""; 
}
Beispiel 3. „Hallo Welt!“ Verwendung von Lambdas

() -> System.out.println("Hello, World!")
Es nimmt nichts entgegen und gibt nichts zurück (wir können es nicht returnvor den Aufruf von setzen System.out.println(), da der println()Rückgabetyp der Methode ist void). Es wird lediglich die Begrüßung angezeigt. Dies ist ideal für eine Implementierung der RunnableSchnittstelle. Das folgende Beispiel ist vollständiger:

public class Main { 
    public static void main(String[] args) { 
        new Thread(() -> System.out.println("Hello, World!")).start(); 
    } 
}
Oder so:

public class Main { 
    public static void main(String[] args) { 
        Thread t = new Thread(() -> System.out.println("Hello, World!")); 
        t.start();
    } 
}
Oder wir können den Lambda-Ausdruck sogar als Objekt speichern und ihn dann an den Konstruktor Runnableübergeben :Thread

public class Main { 
    public static void main(String[] args) { 
        Runnable runnable = () -> System.out.println("Hello, World!"); 
        Thread t = new Thread(runnable); 
        t.start(); 
    } 
}
Schauen wir uns den Moment genauer an, in dem ein Lambda-Ausdruck in einer Variablen gespeichert wird. Die RunnableSchnittstelle sagt uns, dass ihre Objekte eine public void run()Methode haben müssen. Laut Schnittstelle runbenötigt die Methode keine Parameter. Und es gibt nichts zurück, dh sein Rückgabetyp ist void. Dementsprechend erstellt dieser Code ein Objekt mit einer Methode, die nichts entgegennimmt oder zurückgibt. Dies passt perfekt zur Methode der RunnableSchnittstelle run(). Deshalb konnten wir diesen Lambda-Ausdruck in eine RunnableVariable einfügen.  Beispiel 4.

() -> 42
Auch hier wird nichts benötigt, aber die Zahl 42 zurückgegeben. Ein solcher Lambda-Ausdruck kann in eine Variable eingefügt werden Callable, da diese Schnittstelle nur eine Methode hat, die in etwa so aussieht:

V call(),
Wo  V ist der Rückgabetyp (in unserem Fall  int). Dementsprechend können wir einen Lambda-Ausdruck wie folgt speichern:

Callable<Integer> c = () -> 42;
Beispiel 5. Ein Lambda-Ausdruck mit mehreren Zeilen

() -> { 
    String[] helloWorld = {"Hello", "World!"}; 
    System.out.println(helloWorld[0]); 
    System.out.println(helloWorld[1]); 
}
Auch hier handelt es sich um einen Lambda-Ausdruck ohne Parameter und einen voidRückgabetyp (da es keine returnAnweisung gibt).  Beispiel 6

x -> x
Hier nehmen wir eine xVariable und geben sie zurück. Bitte beachten Sie: Wenn nur ein Parameter vorhanden ist, können Sie die Klammern um ihn herum weglassen. Hier ist das Gleiche, aber mit Klammern:

(x) -> x
Und hier ist ein Beispiel mit einer expliziten Return-Anweisung:

x -> { 
    return x;
}
Oder so mit Klammern und einer Return-Anweisung:

(x) -> { 
    return x;
}
Oder mit expliziter Angabe des Typs (und damit mit Klammern):

(int x) -> x
Beispiel 7

x -> ++x
Wir nehmen xes und geben es zurück, aber erst nachdem wir 1 hinzugefügt haben. Sie können dieses Lambda wie folgt umschreiben:

x -> x + 1
In beiden Fällen lassen wir die Klammern um den Parameter- und Methodenkörper sowie die returnAnweisung weg, da sie optional sind. Versionen mit Klammern und einer Return-Anweisung finden Sie in Beispiel 6. Beispiel 8

(x, y) -> x % y
Wir nehmen xund yund geben den Rest der Division von xdurch zurück y. Hier sind die Klammern um die Parameter erforderlich. Sie sind nur dann optional, wenn nur ein Parameter vorhanden ist. Hier mit expliziter Angabe der Typen:

(double x, int y) -> x % y
Beispiel 9

(Cat cat, String name, int age) -> {
    cat.setName(name); 
    cat.setAge(age); 
}
Wir nehmen ein CatObjekt, einen StringNamen und ein int-Alter. In der Methode selbst verwenden wir den übergebenen Namen und das Alter, um Variablen für die Katze festzulegen. Da es sich bei unserem catObjekt um einen Referenztyp handelt, wird es außerhalb des Lambda-Ausdrucks geändert (es erhält den übergebenen Namen und das übergebene Alter). Hier ist eine etwas kompliziertere Version, die ein ähnliches Lambda verwendet:

public class Main { 

    public static void main(String[] args) { 
        // Create a cat and display it to confirm that it is "empty" 
        Cat myCat = new Cat(); 
        System.out.println(myCat);
 
        // Create a lambda 
        Settable<Cat> s = (obj, name, age) -> { 
            obj.setName(name); 
            obj.setAge(age); 

        }; 

        // Call a method to which we pass the cat and lambda 
        changeEntity(myCat, s); 

        // Display the cat on the screen and see that its state has changed (it has a name and age) 
        System.out.println(myCat); 

    } 

    private static <T extends HasNameAndAge>  void changeEntity(T entity, Settable<T> s) { 
        s.set(entity, "Smokey", 3); 
    }
}

interface HasNameAndAge { 
    void setName(String name); 
    void setAge(int age); 
}

interface Settable<C extends HasNameAndAge> { 
    void set(C entity, String name, int age); 
}

class Cat implements HasNameAndAge { 
    private String name; 
    private int age; 

    @Override 
    public void setName(String name) { 
        this.name = name;
    }

    @Override
    public void setAge(int age) {
        this.age = age; 
    } 

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' + 
                ", age=" + age + 
                '}';
    }
}
Ergebnis:

Cat{name='null', age=0}
Cat{name='Smokey', age=3}
Wie Sie sehen können, hatte das CatObjekt einen Zustand, und dann änderte sich der Zustand, nachdem wir den Lambda-Ausdruck verwendet hatten. Lambda-Ausdrücke lassen sich perfekt mit Generika kombinieren. Und wenn wir eine Klasse erstellen müssen Dog, die auch implementiert HasNameAndAge, können wir dieselben Operationen Dogin der main() Methode ausführen, ohne den Lambda-Ausdruck zu ändern. Aufgabe 3. Schreiben Sie eine funktionale Schnittstelle mit einer Methode, die eine Zahl annimmt und einen booleschen Wert zurückgibt. Schreiben Sie eine Implementierung einer solchen Schnittstelle als Lambda-Ausdruck, der „true“ zurückgibt, wenn die übergebene Zahl durch 13 teilbar ist. Aufgabe 4.Schreiben Sie eine funktionale Schnittstelle mit einer Methode, die zwei Strings akzeptiert und auch einen String zurückgibt. Schreiben Sie eine Implementierung einer solchen Schnittstelle als Lambda-Ausdruck, der die längere Zeichenfolge zurückgibt. Aufgabe 5. Schreiben Sie eine funktionale Schnittstelle mit einer Methode, die drei Gleitkommazahlen akzeptiert: a, b und c und außerdem eine Gleitkommazahl zurückgibt. Schreiben Sie eine Implementierung einer solchen Schnittstelle als Lambda-Ausdruck, der die Diskriminante zurückgibt. Falls Sie es vergessen haben: Das ist D = b^2 — 4ac. Aufgabe 6. Schreiben Sie mithilfe der Funktionsschnittstelle aus Aufgabe 5 einen Lambda-Ausdruck, der das Ergebnis von zurückgibt a * b^c. Eine Erklärung von Lambda-Ausdrücken in Java. Mit Beispielen und Aufgaben. Teil 2
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION