Posts mit dem Label Funktionale Programmierung werden angezeigt. Alle Posts anzeigen
Posts mit dem Label Funktionale Programmierung werden angezeigt. Alle Posts anzeigen

Montag, 11. Dezember 2017

Unendliche Streams in Java 8 und 9

[This text is available in English on DZone.]

Mit Lambdas und Streams können wir seit Java 8 endlich etwas funktionaler programmieren. Ein wichtiges Konzept in funktionalen Sprachen sind unendliche Streams, die durch geeignete Bedingungen passend "abgebrochen" werden (die Streams sind natürlich nicht wirklich unendlich, sondern sie werden "lazy" - also erst bei Bedarf - ausgewertet). So etwas gibt es auch in Java, und das möchte ich mit dem folgenden Beispiel zeigen.

Es geht um den Luhn-Algorithmus zur einfachen Berechnung einer Prüfsumme. Inspiriert dazu wurde ich durch den JVM Functional Language Battle von Falk Sippach. Zu sehen gab es in dem Vortrag verschiedene Implementierungen, von klassischem, imperativem Java bis hin zu Scala, Frege und Java mit Vavr (vormals Javaslang).

Eine kurze Zusammenfassung vom Luhn-Algorithmus:
  • Gegeben sei eine nicht negative, ganze Zahl beliebiger Länge.
  • Von rechts nach links wird jede 2. Ziffer der Zahl verdoppelt. Entsteht dabei eine zweistellige Zahl, wird die Quersumme gebildet.
  • Alle so entstandenen Ziffern (einfach und verdoppelt) werden aufsummiert.
  • Die Prüfsumme ist gültig, wenn die Gesamtsumme ohne Rest durch 10 teilbar ist.
Wie kann man das mit Java-8-Streams implementieren? Dazu noch ohne Variablen, Zustandsänderungen und Fallunterscheidung? Beispielsweise so:

import java.util.PrimitiveIterator;
import java.util.stream.IntStream;

public class Luhn {

  public static boolean isValid(String number) {

    PrimitiveIterator.OfInt faktor =
      IntStream.iterate(1, i -> 3 - i).iterator();

    int summe = new StringBuilder(number).reverse()
      .toString().chars()
      .map(c -> c - '0')
      .map(i -> i * faktor.nextInt())
      .reduce(0, (a, b) -> a + b / 10 + b % 10);

    return (summe % 10) == 0;
  }
}

Als Beispiel durchlaufen wir isValid() mit dem String "8763".

Mit IntStream.iterate() erzeugen wir uns einen endlosen (aber lazy berechneten) Stream der Zahlen 1,2,1,2,1,2, ... – das ist der Faktor, mit dem jede Ziffer multipliziert wird.

Dann packen wir den Zahlen-String in einen StringBuilder, weil der eine reverse()-Methode bietet. Damit können wir die einzelnen Ziffern als chars()-Stream vorwärts durchlaufen (und müssen nicht von hinten zählen):

'3', '6', '7', '8'

Jedes Ziffern-char wir nun mit dem ersten map() auf den Ziffern-Wert 0..9 abgebildet und mit dem zweiten map() mit dem nächsten Faktor aus dem endlosen IntStream multipliziert:

3, 12, 7, 16

Mit reduce() berechnen wir nun die Quersumme aller dieser Zahlen, wobei wir für jede Zahl die Zehnerstelle (div 10) und die Einerstelle (mod 10) addieren, also

(0 + 3) + (1 + 2) + (0 + 7) + (1 + 6)

Ergibt 20, und das ist ohne Rest durch 10 teilbar. Somit ist die Prüfsumme gültig.


Mit Java 9 können wir uns das Umwandeln in einen String (und das Umkehren der Zeichenfolge) sparen, indem wir aus der zu prüfenden Zahl einen weiteren unendlichen Stream machen, den wir mit takeWhile() und einem geeigneten Lambda-Prädikat kappen:

import java.util.PrimitiveIterator;
import java.util.stream.IntStream;
import java.util.stream.LongStream;

public class Luhn9 {

  public static boolean isValid(long number) {

    PrimitiveIterator.OfInt faktor =
      IntStream.iterate(1, i -> 3 - i).iterator();

    long summe = LongStream.iterate(number, n -> n / 10)
      .takeWhile(n -> n > 0)
      .map(n -> n % 10)
      .map(i -> i * faktor.nextInt())
      .reduce(0, (a, b) -> a + b / 10 + b % 10);

    return (summe % 10) == 0;
  }
} 

Der chars()-Stream in der Java-8-Lösung war nach der Verarbeitung aller Zeichen zu Ende. LongStream.iterate() in dieser Java-9-Variante teilt die zu prüfende Zahl dagegen endlos immer weiter durch 10, also z.B.

8763, 876, 87, 8, 0, 0, 0, ...

Wir müssen den Stream also nur verarbeiten, solange die Zahl größer Null ist. takeWhile() macht genau das und liefert folgenden endlichen Stream:

8763, 876, 87, 8

Das erste map() liefert einen Stream der letzten Ziffern (mod 10):

3, 6, 7, 8

Der Rest (Multiplizieren mit dem Faktor und Quersummen-Addition) ist dann wieder wie bei der Java-8-Lösung.

Das ist vielleicht noch nicht perfekt funktional, weil wir keine Funktionskomposition beliebiger passender Funktionen durchführen können, sondern auf die vorhandene Stream-API angewiesen sind. Aber für Java-Bordmittel ist das doch gar nicht so schlecht.


Und wer noch nicht genug davon hat: Ein anderes schönes Beispiel für unendliche Java-Streams ist die Berechnung von Kaprekar-Zahlen, was kürzlich als Challenge auf dev.to lief. Neben takeWhile() kommt bei der Java-Lösung noch limit() zum Einsatz, um einen unendlichen Stream nicht mit einer Bedingung, sondern mit einer festen Anzahl zu begrenzen.

Samstag, 19. März 2016

Closures in Clojure

Eine Sprache, die nach Closures benannt ist (und genauso ausgesprochen wird), sollte ziemlich gut mit Closures umgehen können :-). Das Zähler-Beispiel für Java, Groovy, Scala etc. sieht in Clojure wie folgt aus:

; closures.clj

(defn zaehlerMitStartwert [startwert]
  (let [zaehler (atom startwert)]
    (fn [] (swap! zaehler inc))))

(def next1 (zaehlerMitStartwert 10))
(def next2 (zaehlerMitStartwert 20))

(println (next1))  ;; 11
(println (next2))  ;; 21
(println (next2))  ;; 22
(println (next1))  ;; 12

In der Funktion zaehlerMitStartwert wird im let-Block ein lokales Binding für zaehler angelegt. Der Wert von zaehler ist ein Atom mit dem übergebenen startwert. Ein Atom speichert in Clojure einen Zustand, der threadsicher ausgetauscht werden kann. Rückgabe von zaehlerMitStartwert ist eine Funktion ohne Parameter: (fn [] ...) - dies ist die Closure, die die freie Variable zaehler außerhalb der Closure-Funktion bindet (umschließt). Die Closure-Funktion verändert (swap!t) den zaehler-Wert mithilfe der inc-Funktion und gibt den neuen (reingeswap!ten) Wert zurück.

Dann definieren wir zwei globale Variablen next1 und next2, die mit je einer Closure-Instanz initialisiert werden. Diese Funktionen werden mit der Clojure- bzw. Lisp-typischen Syntax (next1) aufgerufen (statt next1() o.ä.).

Mittwoch, 16. März 2016

Closures in Groovy

Beim JavaLand 2016 vor einer Woche hat Dierk König einen schönen Einstieg in die elegante und kompakte Ausdrucksweise von Groovy gegeben. Dabei hat er als Closure-Beispiel einen Zähler verwendet, den ich hier – weil er so gut zu meinen bisherigen Closure-Beispielen (u.a. für Java, JavaScript und Scala) passt – zeigen möchte (Fehler im Code gehen selbstverständlich auf mein Konto ;-):

// closures.groovy

Closure zaehlerMitStartwert(startwert) {
  return {
    startwert++
  }
}

def next1 = zaehlerMitStartwert(10)
def next2 = zaehlerMitStartwert(20)

println next1()  // 10
println next2()  // 20
println next2()  // 21
println next1()  // 11

Das return in der Funktion zaehlerMitStartwert gibt die Closure – den darauffolgenden Block mit geschweiften Klammern und der Zähl-Anweisung – zurück. Im Block selbst ist kein return notwendig, weil hier für den Compiler klar ist, dass die letzte (und hier einzige) Anweisung im Block das Ergebnis der Block-Funktion ist. Man sieht sehr schön, dass Groovy-Closures problemlos freie Variablen außerhalb des Closure-Blocks binden - so, wie das auch bei Scala der Fall ist (aber anders als bei Java, wo normalerweise nur final-Werte und nur mit Tricks Variablen gebunden werden können).

Wer das Groovy-Skript ausprobieren möchte, kann es einfach in die Groovy-Web-Console kopieren und dort ausführen.

Dienstag, 1. März 2016

Closures in Java

Java 8 ist nun bald zwei Jahre alt – eine gute Gelegenheit, meine kleine Closures-Reihe weiterzuführen. Nach Scala, JavaFX und JavaScript sind heute also Closures in Java an der Reihe. Das Zähler-Beispiel sieht mit den Lambda-Ausdrücken aus Java 8 so aus:
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.IntSupplier;

public class ClosuresJava8 {

  static IntSupplier zaehlerMitStartwert(int startwert) {

    AtomicInteger n = new AtomicInteger(startwert);

    IntSupplier s = () -> {
      return n.incrementAndGet();
    };

    return s;
  }

  public static void main(String[] args) {

    IntSupplier next1 = zaehlerMitStartwert(10);
    IntSupplier next2 = zaehlerMitStartwert(20);

    System.out.println( next1.getAsInt() ); // 11
    System.out.println( next2.getAsInt() ); // 21
    System.out.println( next2.getAsInt() ); // 22
    System.out.println( next1.getAsInt() ); // 12
  }
}
Die Methode zaehlerMitStartwert() gibt eine IntSupplier-Lambda-Funktion zurück. IntSupplier ist ein sogenanntes "funktionales Interface", d.h. ein Interface mit genau einer Methode (in diesem Fall getAsInt()). Ein "Supplier" bezeichnet dabei eine Methode ohne Parameter, die einen Rückgabewert liefert.

Der Lambda-Ausdruck ist dabei so etwas wie eine Kurzschreibweise für ein anonymes Objekt des IntSupplier-Interfaces, wobei das new, der Interface-Name und der Methodenname weggelassen werden. Die Anweisung im Lambda-Ausdruck ("return n.incrementAndGet();") wird dabei zum Rumpf der unsichtbaren getAsInt()-Methode.

Im Lambda-Ausdruck wird der übergebene Startwert erhöht und zurückgegeben. Allerdings müssen die gebundenen Variablen außerhalb des Lambda-Ausdrucks in Java final oder "effectively final" sein (d.h. sie dürfen nicht verändert werden, damit der Compiler final annehmen kann). Deshalb lassen wir den Lambda-Ausdruck ein AtomicInteger-Objekt binden – der Inhalt des AtomicInteger-Objektes ist veränderbar, die Referenz darauf ist aber wie gewünscht final.

Im obigen Beispiel wird die Lambda-Funktion nur zum einfacheren Verständnis in der lokalen Variablen s zwischengespeichert. Man kann den Lambda-Ausdruck auch direkt als Methodenergebnis zurückgeben:
  static IntSupplier zaehlerMitStartwert(int startwert) {

    AtomicInteger n = new AtomicInteger(startwert);

    return () -> {
      return n.incrementAndGet();
    };
  }
Und da unser Lambda-Ausdruck nur aus einer einzigen Anweisung besteht, deren Ergebnis als Funktionsergebnis zurückgegeben wird, kann man das noch weiter kürzen und die geschweiften Klammern und das return im Lambda-Rumpf weglassen:
  static IntSupplier zaehlerMitStartwert(int startwert) {

    AtomicInteger n = new AtomicInteger(startwert);

    return () -> n.incrementAndGet();
  }
Das sieht doch schon fast richtig funktional aus :-)

Donnerstag, 15. März 2012

Typinferenz in Java

Durch das verstärkte Interesse an funktionalen Sprachen wird auch immer häufiger von Typinferenz gesprochen, also vom automatischen Ermitteln eines passenden Datentyps durch den Compiler.

Beispielsweise legt man in Scala eine Liste ganzer Zahlen mit folgendem Ausdruck an:

val zahlen = List[Int](1,2,3)

Oder noch kürzer:

val zahlen = List(1,2,3)

Der Compiler ermittelt also einen möglichst spezifischen Typen für die rechte Seite des Ausdrucks (hier eine Liste von Ints) und verwendet ihn automatisch als Datentyp für die Wertdeklaration auf der linken Seite.

Seit Version 7 beherrscht nun auch Java eine offensichtliche Form der Typinferenz:

List<Integer> liste = new ArrayList<>();

Man kann auf der rechten Seite die Typangabe bei der generischen ArrayList weglassen (die Angabe der leeren spitzen Klammern, des "Diamanten", ist aber notwendig), und der passende Typ (Integer) wird automatisch von der linken Seite übernommen. Die Inferenz von links nach rechts ist auch der wichtigste Unterschied zu der üblichen Typinferenz funktionaler Sprachen – in der Praxis ist deren Typinferenz von rechts nach links praktischer, da sie mehr Schreibarbeit spart.

Was nicht so offensichtlich ist: Bereits seit Java 5 gibt es eine ähnliche Form der Typinferenz. Definiert man eine Methode mit lokalem generischen Parameter:

public static <T> T typecast(Object obj) {
@SuppressWarnings("unchecked")
T gecastet = (T) obj;
return gecastet;
}

kann man sie wie folgt aufrufen:

String s = typecast("Hallo");

Die Methode "typecast" hat in diesem Fall tatsächlich den Rückgabetyp "String", abhängig vom Typ der deklarierten Variablen auf der linken Seite. Ob diese Methode in der Praxis sinnvoll ist, sei mal dahingestellt – bei Übergabe eines Nicht-String-Objekts geht der Typecast in der Methode zur Laufzeit mit einer ClassCastException schief. Aber sie demonstriert sehr gut die seit langem in Java vorhandene (wenn auch sehr eingeschränkte) Typinferenz.

Sonntag, 20. März 2011

Monaden in Scala

Am vergangenen Wochenende habe ich beim MATHEMA Campus 2011 einen Vortrag über Monaden in Scala gehalten (Folien hier).

Monaden sind ein etwas sperriges Konzept, das in rein funktionalen Sprachen wie Haskell u.a. für eine vernünftige Ein-/Ausgabeprogrammierung notwendig ist. Für Scala sind Monaden vielleicht nicht ganz so wichtig, aber auch mit Scala kann man sinnvoll monadisch programmieren – und das Schöne daran: Über die ganze komplizierte mathematische Theorie dahinter muss man sich keine Gedanken machen. Im Gegenteil, wer schonmal ein bisschen Scala programmiert hat, wird dabei vermutlich (unbewusst) auch Monaden genutzt haben.

Was sind diese Monaden? Ein abstrakter Datentyp für verkettbare Berechnungen mit folgenden Eigenschaften:
  • Ein Typkonstruktor wie List[A] (mit z.B. List[Int] als Ausprägung).
  • Eine Funktion, um einen Wert im Typ "einzuwickeln". Das kann der Konstruktor sein, z.B. new List(1) bzw. List(1), aber häufig wird diese Funktion return, unit, lift oder pure genannt.
  • Eine Funktion, um die enthaltenen Werte zu verrechnen, aber nach der Berechnung im Typ verpackt zu lassen. Übliche Namen sind bind oder (in Scala) flatMap.
Die Monadengesetze müssen von den Funktionen eingehalten werden, aber das lassen wir mal außen vor. Klingt kompliziert? Schauen wir uns das in der Praxis an:
case class MiniMonade[A](wert:A) {

def flatMap[B](f: A => MiniMonade[B]) = f(wert)

def map[B](f: A => B): MiniMonade[B]
= MiniMonade(f(wert))
}
Die Mini-Monade soll also genau einen Wert des generischen Typs "A" speichern und verarbeiten können. Listen sind auch Monaden und können entsprechend beliebig viele Werte verarbeiten. In unserer Monade ist zusätzlich noch die Funktion map implementiert, damit wir Objekte dieser Klasse in den for-Comprehensions von Scala einsetzen können. Und genau das ist auch der häufigste Anwendungsfall für Monaden in Scala:
val m1 = MiniMonade(2)
val m2 = MiniMonade(3)

val erg = for { x <- m1; y <- m2 } yield x*y;

println( erg )
In dieser for-Comprehension werden alle Werte aus den beiden Monaden-Objekten miteinander mit x*y verrechnet und landen anschließend (durch die Magie der Monaden-Funktionen) wieder in einem Monaden-Objekt. Da unsere Objekte jeweils nur einen Wert speichern, wird nur 2*3 berechnet:
HeartOfGold:~ much$ scala MiniMonade.scala
MiniMonade(6)
Das scheint unnötig viel Aufwand für eine simple Multiplikation zu sein... Aber folgendes Beispiel dürfte – so oder in ähnlicher Form – jeder schonmal programmiert haben, und das ergibt sicher mehr Sinn:
val zeilen = List(10,20)
val spalten = List(1,2)

val summen = for {z <- zeilen; s <- spalten} yield z+s;

println( summen )
// List(11, 12, 21, 22)
Andere gebräuchliche monadische Typen sind (neben vielen weiteren) Map und Option, und alle diese Klassen können in einer for-Comprehension kombiniert werden.

Die Verwendbarkeit in for-Comprehensions ist in Scala sicherlich der wichtigste Grund, warum man geeignete eigene Klassen monadisch machen sollte. Würden wir noch withFilter und foreach implementieren, könnten wir unsere Monade außerdem in weiteren for-Varianten einsetzen.

Beim diesjährigen Herbstcampus werde ich einen Einsteiger-Vortrag (OO-Vorkenntnisse reichen) zu diesem Thema halten.

Freitag, 26. Februar 2010

Closures in JavaScript

Nachdem ich schon Beispiele für Closures (Funktionsabschlüsse) in JavaFX und Scala vorgestellt hatte, schauen wir uns dasselbe Beispiel in JavaScript (ECMAScript) an:
// closures.js

function zaehlerMitStartwert(startwert) {
return function() {
return startwert++
}
}

next1 = zaehlerMitStartwert(10)
next2 = zaehlerMitStartwert(20)

document.writeln( next1() ) // 10
document.writeln( next2() ) // 20
document.writeln( next2() ) // 21
document.writeln( next1() ) // 11

Sehr viel mehr gibt es dazu eigentlich nicht zu sagen, außer dass es
  1. wirklich so einfach ist (was auch zu Problemen führen kann)
  2. schon seit den ersten JavaScript-Versionen (und damit seit über 10 Jahren) zur Verfügung steht und
  3. im Gegensatz zu JavaFX Script und Scala dynamisch typisiert ist; zudem ist keine zusätzliche lokale Variable nötig, weil der Übergabeparameter startwert bereits eine veränderbare Variable ist. Beides ist im Hinblick auf stabile, wartbare Software nicht unbedingt als positiv zu bewerten.
Viele moderne JavaScript-Bibliotheken machen starken Gebrauch von solchen Funktionsliteralen und Closures, beispielsweise jQuery.

Sonntag, 31. Januar 2010

Closures in Scala

Als funktionale Sprache unterstützt Scala Funktionen höherer Ordnung (first-class functions) und Funktionsabschlüsse (Closures). In dem Beitrag über Closures in JavaFXScript hatte ich bereits gezeigt, wie dort Closures definiert und genutzt werden. Wie programmiert man nun Closures in Scala?
// closures1.scala

def zaehlerMitStartwert(startwert: Int): (() => Int) = {
var n = startwert
def nplus1(): Int = { n=n+1; n }
nplus1
}

val next1 = zaehlerMitStartwert(10)
val next2 = zaehlerMitStartwert(20)

println( next1() )
println( next2() )
println( next2() )
println( next1() )
Wir definieren eine Funktion zaehlerMitStartwert(), die den Startwert als Int-Parameter übergeben bekommt. Rückgabe dieser Funktion ist eine Funktion, die keine Parameter hat, aber einen Int-Wert zurückgibt.

Innerhalb der äußeren Funktion legen wir eine Zählvariable n an, da der Übergabeparameter startwert unveränderlich ist. Dann definieren wir eine verschachtelte Funktion nplus1(), die auf die Zählvariable n eins draufzählt und als letzten Ausdruck der Funktion das hochgezählte n zurückgibt. Hier findet der Funktionsabschluss statt - das Binden der Variablen n, die als lokale Variable in der umgebenden Funktion definiert ist. Als letzten Ausdruck in der äußeren Funktion geben wir die Funktion nplus1 als Ergebnis zurück.

Das ganze geht auch etwas kürzer und "funktionaler", wenn man die innere Funktion nicht explizit definiert, sondern als letzten Ausdruck der äußeren Funktion gleich ein entsprechendes Funktionsliteral hinschreibt:
// closures2.scala

def zaehlerMitStartwert(startwert: Int) = {
var n = startwert
() => { n=n+1; n }
}

val next1 = zaehlerMitStartwert(10)
val next2 = zaehlerMitStartwert(20)

println( next1() )
println( next2() )
println( next2() )
println( next1() )
Beide Skripte liefern dieselbe Ausgabe:
HeartOfGold:~ much$ scala closures2.scala
11
21
22
12
Wenn man den Scala-Interpreter mit scala -savecompiled closures2.scala aufruft, erhält man ein JAR-Archiv, in dem man sich die generierten Java-Bytecode-Dateien anschauen kann. In diesem Fall werden vier class-Dateien erzeugt.

Mittwoch, 26. August 2009

Closures in JavaFX Script

JavaFX Script (die Programmiersprache für Suns neue RIA-Technologie JavaFX) ist eine objektorientierte, deklarative und funktionale Programmiersprache.

Als funktionale Sprache unterstützt sie Funktionen höherer Ordnung (first-class functions) und Funktionsabschlüsse (Closures). Ersteres bedeutet, dass Funktionen selber Werte sind – sie können also als Parameter übergeben und zurückgegeben werden. Letzteres erlaubt den Funktionswerten, dass sie sich den Zustand ihrer Umgebung (die lokalen Variablen) bei ihrer Erzeugung merken können.

Für viele sind Closures seltsame Konstrukte und ihre Einsatzmöglichkeiten nicht offensichtlich. Daher im Folgenden ein kleines, relativ leicht verständliches Beispiel, in dem mehrere Zähler mit individuellen Startwerten erzeugt und benutzt werden:
// closure.fx

function zaehlerMitStartwert(startwert: Integer) {
var n = startwert;
return function(): Integer { return n++ }
}

var next1 = zaehlerMitStartwert(10);
var next2 = zaehlerMitStartwert(20);

println( next1() ); // 10
println( next2() ); // 20
println( next2() ); // 21
println( next1() ); // 11
Wer das Beispiel ausprobieren möchte, installiert sich das JavaFX 1.2 SDK und nutzt die Kommandozeile (oder NetBeans oder Eclipse mit dem JavaFX-Plugin):
Straylight:~ much$ javafxc closure.fx
Straylight:~ much$ javafx closure
10
20
21
11
Die ausgegrauten Elemente sind nicht wirklich notwendig und sollen nur das Skript für Java-Programmierer leichter verständlich machen. "return" ist an beiden Stellen optional, da der letzte Ausdruck in einer Funktion gleichzeitig deren Ergebnis definiert. Der Rückgabetyp ":Integer" der inneren, anonymen Funktion ist optional, da aus dem Datentyp des Ergebnisses der Rückgabetyp durch Typinferenz ermittelt werden kann.

Trotz (bzw. gerade wegen) dieser impliziten Typisierung ist JavaFX Script im Gegensatz zu Skriptsprachen wie JavaScript statisch und streng typisiert. Bereits der Compiler ermittelt also die Datentypen und Signaturen von Variablen und Funktionen, sofern sie nicht explizit angegeben sind. Im Beispiel hat die Variable n also den Datentyp Integer, die Variablen next1 und next2 haben den Typ function():Integer und zaehlerMitStartwert hat den Typ function(:Integer):function():Integer :-)

Wie funktioniert das Skript? Beim Aufruf der Funktion zaehlerMitStartwert wird eine Funktion zurückgegeben, die bei jedem Aufruf die Variable n um eins erhöht zurückgibt. Obwohl die Variable n zur äußeren Funktion gehört und damit beim Aufruf der zurückgegebenen Funktion mit next1() bzw. next2() eigentlich gar nicht mehr vorhanden ist, merkt sich die innere Funktion die lokale Variable separat für jede zurückgegebene innere Funktion – und genau das macht sie zur Closure.

Man kann sich Closures als Objekte vorstellen, die aus einer einzigen Methode/Funktion bestehen und wie Objekte zusätzlich einen Zustand haben. Schön sehen kann man dies an den generierten Java-Bytecode-Klassendateien: closure.class und closure$1.class. Die innere, anonyme Funktion wird für die JVM also einfach als innere, anonyme Java-Klasse closure$1.class abgebildet.

Closures sind prima geeignet, um damit z.B. Event-Handler zu definieren, denen man zusätzliche Informationen mitgeben kann (bei Farb-Setz-Buttons in einem Grafikprogramm beispielsweise die zu setzende Farbe). Dadurch kann man häufig auf das Schreiben von Event-Handler-Klassen verzichten, auch wenn dies in JavaFX Script ebenfalls möglich ist.

Vielleicht hat man es gemerkt: Ich halte JavaFX Script trotz des Namens ganz und gar nicht für eine Skriptsprache. Meines Erachtens wurde die Sprache vor allem deshalb so genannt, um zu zeigen, dass man damit in Wettbewerb zu Skriptsprachen wie Ruby tritt, die als agil und produktiv empfunden werden. JavaFX Script zeigt dabei sehr schön, dass sich Produktivität und statische, strenge Typisierung überhaupt nicht ausschließen müssen.