Dienstag, 30. November 2010

VisualVM 1.3.x statt Eclipse TPTP?

Vor zwei Wochen wurde bekannt gegeben, dass das Eclipse-Projekt für Test- und Performance-Werkzeuge – TPTP – nach dem kommenden Update auf Version 4.7.2 (geplant für Februar 2011) nicht mehr weiterentwickelt wird.

Einer der Aspekte, die mir an TPTP gefallen haben, war das Probekit, mit dem man kleine Java-Schnipsel an bestimmte Stellen einer Java-Klasse (Methoden-Ein- und -Ausgang etc.) einweben lassen konnte, um die Klassen zur Laufzeit genauer zu untersuchen.

Ein möglicher Ersatz steht schon in den Startlöchern. Mitte des Jahres wurde VisualVM 1.3 veröffentlicht, das mittlerweile in der Version 1.3.1 verfügbar ist. Darin enthalten ist das Tracer-Plugin, mit dem sich diverse "Probes" für eine laufende Anwendung aktivieren lassen, die dann synchron untereinander auf einer Zeitleiste dargestellt werden:

Derzeit gibt es nur vordefinierte Probes für Swing, JavaFX sowie für diverse weitere Pakete der Standard-Klassenbibliothek (Collections, I/O etc.). Das Tracer-Framework soll sich aber einfach mit eigenen Probes erweitern lassen (auch wenn ich noch keinen Link zu einer aktuellen Entwickler-Dokumentation gefunden habe) – und vielleicht gibt es ja in absehbarer Zeit eine Probe zum AOP-mäßigen Einweben von kleinen Code-Stücken? Dieser Wunsch muss erlaubt sein, schließlich ist ja bald Weihnachten :-)

Ob man VisualVM separat herunterladen muss oder ob es im installierten JDK bereits enthalten ist, kann man auf der Release-Übersicht herausfinden. Das aktuelle Java 6 Update 22 bringt leider immer noch die ältere VisualVM-Version 1.2.2 mit.

Montag, 15. November 2010

Oracle bringt Java SE 7 für Mac OS X

... und Apple wird auch in Mac OS X 10.7 "Lion" noch die eigene Java SE 6-Implementation bereitstellen. Das sind kurz zusammengefasst die Ergebnisse der letzten Tage.

Nachdem es vor drei Wochen recht düster für die Zukunft von Java auf Mac OS X ausgesehen hatte, weil Apple die eigene Java-Implementierung abgekündigt, aber keinen Ersatz als Perspektive geboten hatte, sieht es nun so aus, als ob wir genau die Lösung bekommen, die von vielen favorisiert wurde: Apple bringt die meisten Teile seiner Java-Implementation als Open Source in das OpenJDK-Projekt ein, und Oracle wird daraus – beginnend mit Java SE 7 – offizielle Java-Releases für Mac OS X bauen.

Es ist noch nicht ganz klar, wann Java SE 7 für Mac OS X verfügbar sein wird und wie die Quelltexte im Detail zur Verfügung gestellt werden. Aber die Zukunft für Java auf Mac OS X dürfte damit sichergestellt sein.

Nebenbei hat Apple in der Pressemitteilung bekannt gegeben, dass auch das im nächsten Jahr erscheinende Mac OS X 10.7 "Lion" noch die eigene Java SE 6-Implementation enthalten wird, so dass für die Übergangszeit auf Oracles Mac-Java-Implementation eine klare Perspektive besteht.

Na also. Warum denn nicht gleich so?

Donnerstag, 11. November 2010

Scala 2.8.1

Vorgestern wurde mit nur wenigen Tagen Verspätung Scala 2.8.1 freigegeben.

Neben zahlreichen Bugfixes enthält das Update vor allem eine verbesserte Version von Scaladoc. Ein Ergebnis dieses Werkzeugs ist beispielsweise die API-Dokumentation der Scala-Standard-Bibliothek.

Scala 2.8.1 ist vollständig binärkompatibel mit der vorangegangenen Version 2.8.0 (was davor durchaus nicht selbstverständlich war, nun aber erklärtes Ziel zur Stabilisierung der Softwareentwicklung mit Scala ist).

Seit heute liegt außerdem die Scala IDE für Eclipse in einer aktualisierten Version vor. Durch die Binärkompatibilität der Scala 2.8.x-Versionen kann man erstmalig die neueste Scala IDE einsetzen und damit bestehende Projekte wahlweise weiterhin mit Scala 2.8.0 übersetzen, bis eine Umstellung auf 2.8.1 geeignet erscheint.

Donnerstag, 21. Oktober 2010

@Deprecated Java für Mac OS X

Es musste ja irgendwann passieren: Nachdem schon Flash in Ungnade gefallen war, hat Apple nun keine Lust mehr auf Java...

In den Release Notes zum gestern erschienenen "Java for Mac OS X 10.6 Update 3", das Java SE 6 auf Version 1.6.0_22 aktualisiert, findet sich an prominenter Stelle der Hinweis, dass Apples eigene Java-Implementation ab sofort als veraltete Technologie gilt und in künftigen Mac OS X-Versionen fehlen könnte.

Auch wenn direkt unter dieser Ankündigung beschrieben ist, dass und wie mit diesem Update Java Virtual Machines (JVMs) anderer Hersteller leichter ins System eingebunden werden können (was ich in einem folgenden Blog-Eintrag beschreibe) und auch die exakte Wortwahl der Apple-Java-Abkündigung fast impliziert, dass ein anderer Hersteller in die Bresche springen wird – gesichert ist dies nicht.

Bis also Oracle oder IBM oder irgendwer sonst (Google?) offiziell bekannt gibt, dass sie eine Java-Implementierung für Mac OS X anbieten werden, müssen wir leider davon ausgehen, dass Java auf dem Mac tot ist.

Dies dürfte extrem negative Auswirkungen auf den Einsatz von Macs in Unternehmen haben, da dort Java-Anwendungen häufig in der einen oder anderen Form benötigt werden. Ebenso wird der Mac damit für Bildungseinrichtungen und insbesondere Hochschulen uninteressant, da dort oft Java als Lehrsprache eingesetzt wird. Und die Java-Entwickler-Gemeinde, in der sich (zumindest gefühlt) überdurchschnittlich viele Mac-Anwender befinden, wird sich neue Hardware-Investitionen und Upgrades auf kommende Mac OS X-Versionen gut überlegen.

Zu hoffen bleibt, dass die Ankündigung nur eine Kommunikations-Katastrophe mit schlechtem Timing war. Andererseite werden, sofern man diversen Internet-Quellen glauben darf, Java-Anwendungen für den kommende "Mac App Store" nicht akzeptiert werden, da es sich um veraltete Technologie handelt. Und das sieht dann schon eher nach Absicht aus...

Abwarten und Kaffee trinken.

Donnerstag, 14. Oktober 2010

Hibernate 3.6 mit performanterem Envers und ohne Java 1.4

Gestern gab es das zweite, große Hibernate-Release in diesem Jahr: Hibernate 3.6. So kurz nach Hibernate 3.5, das vor allem die JPA 2.0-Kompatibilität brachte, bringt die neue Version nicht sehr viele neue Features mit, sondern hat vor allem dringend notwendige interne Änderungen und Re-Implementierungen erfahren:
  • Java 1.4 wird nicht mehr unterstützt, Voraussetzung ist nun also Java 5.0 und neuer.
  • Das interne Typsystem wurde überarbeitet. Vor allem Implementierungen benutzerdefinierter Mapping-Typen müssen nun vermutlich angepasst werden.
  • Wer XML-Mappings verwendet, sollte die DTDs von http://hibernate.sourceforge.net/ auf http://www.hibernate.org/dtd umstellen.
  • Und schließlich enthält das mitgelieferte Envers eine neue Audit-Strategie, ValidityAuditStrategy. Damit kann nun nicht nur der Anfangszeitpunkt einer Revision gespeichert werden, sondern auch der Endzeitpunkt. Während das Speichern dadurch etwas mehr Zeit und eine zusätzliche Spalte in der Datenbank-Tabelle benötigt, wird das Lesen historischer Daten deutlich performanter.

Donnerstag, 7. Oktober 2010

Scala-Roadmap, -Literatur u.a.

Es tut sich was im Scala-Universum. Laut Roadmap soll noch in diesem Monat Version 2.8.1 veröffentlicht werden. Zeitlich sieht es gut aus, denn die Version liegt bereits als zweiter Release Candidate vor. Mit diesem kleinen Update werden hauptsächlich Fehler beseitigt, die sich durch die starken internen Änderungen beim Sprung auf Version 2.8 eingeschlichten hatten.

Das nächste größere Update wird Scala 2.9 sein, das für Anfang kommenden Jahres geplant ist. Darin sollen vor allem parallele Kollektionen enthalten sein.

Um Firmen bei der Einführung von Scala und bei der Migration von älteren Scala-Versionen zu unterstützen, hat Martin Odersky, der Erfinder der Sprache, vor kurzem Scala Solutions gegründet. Ein guter und notwendiger Schritt, damit Scala im kommerziellen Umfeld die Akzeptanz findet, die diese Sprache verdient! (Scala-Workshops kann man natürlich auch anderswo buchen ;-)

Und noch ein bisschen Werbung in eigener Sache: Der Galileo-Verlag hat heute mein Buch "Scala. Der Schnelleinstieg für Entwickler." angekündigt, das im kommenden Jahr erscheinen wird. Bis zur Veröffentlichung bleibt noch genug zu tun, aber es macht Spaß, nach über fünf Jahren mal wieder ein Buch entstehen zu sehen :-)

Dienstag, 28. September 2010

Eclipse 3.6 und @SuppressWarnings("unchecked")

Eclipse 3.6 ist schon seit einiger Zeit auf dem Markt, aber die ganzen neuen kleinen Features entdeckt man oft erst nach und nach.

Ergänzend zu einem früheren Posting habe ich gerade gesehen, dass die "Quick Fix"-Funktion bei einer "Type safety"-Warnung nun nach Möglichkeit anbietet, die passende Annotation direkt an die Variablendeklaration zu schreiben (und nicht nur über die gesamte Methode):

Nett!

Samstag, 31. Juli 2010

Ant Filter-Copy-Task und Zeichenkodierung

Ein Eintrag aus der Rubrik "kleiner Fehler, große Wirkung": Resource-Properties-Dateien wurden für eine Web-Anwendung mit einem Ant-Skript aus den Projektordnern in die passenden Ordner der Web-Applikation umkopiert. Bei manchen Properties-Dateien wurden die darin enthaltenen Umlaute im Browser manchmal (je nach Applikations-Server und je nach Rechner, auf dem die Web-Anwendung gebaut wurde) falsch dargestellt.

Ursache des Problems war ein copy-Task, der die Datei nicht 1:1 umkopiert, sondern mit einem filterset bestimmte Token ersetzt hat. Je nach Systemeinstellung kamen dann in der Web-Anwendung Umlaute (bzw. allgemein Sonderzeichen) an, die im Browser korrekt angezeigt werden konnten – oder eben nicht.

Die Lösung des Problems ist, bei Filter-Copy-Tasks die Kodierung explizit anzugeben, damit nicht die System-Default-Kodierung verwendet wird (die Doku erwähnt dies am Ende des Dokuments). Bei Properties-Dateien ist ISO-Latin-1 (ISO-8859-1) meist eine erste, gute Wahl (sofern die gesamte Web-Anwendung nicht auf UTF ausgelegt ist):
<copy
todir="${webapp}/WEB-INF/classes"
file="${src}/MyResources.properties"
encoding="ISO-8859-1"
overwrite="true">

<filterset>
<filter token="COMPILETIME" value="${DSTAMP}-${TSTAMP}"/>
</filterset>

</copy>
Entstanden ist der Bug wohl durch Copy&Paste, wobei aus einem fileset – ohne Filterung und damit ohne die Notwendigkeit, eine Zeichenkodierung anzugeben – ein filterset wurde.

Mittwoch, 14. Juli 2010

Scala 2.8 und Lift 2.0

Knapp ein dreiviertel Jahr nach der letzten offiziellen Version 2.7.7 ist es heute endlich soweit: Scala 2.8 wurde veröffentlicht! Neben zahlreichen Bugfixes gibt es viele Neuerungen:
  • leichtgewichtigere, performantere Aktoren
  • Unterstützung für Continuations
  • verbesserte XML-Bibliothek
  • Überarbeitete Kollektions-Bibliothek und Array-Implementation
  • Benannte und Default-Argumente
  • Package-Objekte
  • bessere Unterstützung für (verschachtelte) Java-Annotationen
  • deutlich verbesserte Scala-Interpreter-Shell (REPL), u.a. mit Tab-Eingabevervollständigung
  • u.a.
Die Werkzeuge Sbaz und Scaladoc liegen in Version 2 vor, der Decompiler Scalap wurde an aktuelle Sprachkonstrukte angepasst. Die Scala IDE für Eclipse wurde intensiv überarbeitet, wodurch sie nun u.a. besser in die Java-Werkzeuge von Eclipse eingebunden ist.


Bereits vor zwei Wochen wurde das Scala-Web-Framework Lift 2.0 veröffentlicht. Neben der bisher schon sehr guten Ajax- und Comet-Unterstützung gibt es u.a. folgende Neuerungen:

Zum Schluss ein bisschen Werbung in eigener Sache: Wer mehr über Scala erfahren möchte, darf gerne an meinem nächsten Scala-Workshop teilnehmen, der Ende November in Köln stattfindet!

One more thing...

Dienstag, 15. Juni 2010

NetBeans 6.9 inkl. JavaFX Composer

Heute hat Oracle/Sun NetBeans 6.9 fertig gestellt und veröffentlicht. Eines der wichtigsten neuen Merkmale dürfte der nun standardmäßig integrierte JavaFX Composer sein, mit dem sich Formulare und Grafiken für JavaFX 1.3 visuell erstellen lassen:

Mal abwarten, wie sich der GUI-Editor in der Praxis bewährt. Aber die ersten Versuche sehen recht vielversprechend aus.

Im Bereich "Java EE" ist die Unterstützung für den JSR-299 (CDI) sowie für Spring 3.0 erwähnenswert. Außerdem ist der Application Server GlassFish in der Version 3.0.1 integriert.

Montag, 31. Mai 2010

JavaFX 1.3

Nur der Vollständigkeit halber... Bereits Ende letzten Monats hat Oracle/Sun JavaFX 1.3 veröffentlicht. Die wichtigsten Neuerungen sind
  • neue Controls (u.a. endlich eine ChoiceBox)
  • neue, brauchbare Layouts
  • bessere CSS-Unterstützung
  • bessere Performance und weniger Speicherverbrauch.
Beschreibungen und Zusammenfassungen der Änderungen und Neuerungen finden sich u.a. hier, hier und hier.

Wichtiger für die Akzeptanz von JavaFX ist m.E. aber, dass mit der Beta-Version von NetBeans 6.9 der JavaFX Composer mitgeliefert wird, mit dem Benutzeroberflächen (GUIs) – sowohl Masken als auch Grafiken – visuell zusammengestellt werden können.

Die Migration bestehender Java FX 1.2-Anwendungen auf die neue Version ist hier beschrieben.

Dienstag, 20. April 2010

Hibernate 3.5 mit JPA 2.0 und Envers

Einige Wochen war es ruhig in diesem Blog, aber mit der Veröffentlichung unseres aktuellen Projekts Klaas 1.0 hatten wir alle Hände voll zu tun :-)

In der Zwischenzeit wurde nach vielen Monaten der Entwicklung Ende März endlich Hibernate 3.5 fertiggestellt. Mittlerweile steht sogar schon das erste Bugfix-Release Hibernate 3.5.1 zur Verfügung.

JPA 2.0 wird nun vollständig unterstützt, und mit Envers ist eine Bibliothek zur automatischen temporalen Datenhaltung (Historisierung bzw. Versionierung) enthalten. Außerdem wurde die Abhängigkeitsverwaltung der Hibernate-Teilprojekte vereinfacht, denn aufeinander abgestimmte Versionen der Hibernate-Annotationen, des Hibernate-EntityManagers und von Envers sind nun im Hibernate-Core-JAR enthalten.

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.

Dienstag, 16. Februar 2010

Hibernate/JPA, hashCode() und Eclipse

Entitäten in Hibernate/JPA haben oft einen synthetischen (technischen) Primärschlüssel, der im folgenden Beispiel als Long id implementiert wird. Sofern es keine zusätzlichen fachlichen Schlüsselkandidaten gibt, muss man die hashCode()-Methode für Hibernate/JPA so implementieren, dass sie ausschließlich mit dieser Id arbeitet. (Es gibt auf hibernate.org eine lange Diskussion zu diesem Thema, denn die "offiziell" vorgeschlagene Variante, "halb-eindeutige" Felder zu verwenden, macht in der Praxis meistens mehr Probleme als die Id-Variante.)

Damit man hashCode() (und das zwingend dazu gehörende equals()) nicht immer wieder von Hand neu schreiben muss, bietet Eclipse über Source > Generate hashCode() and equals() die Möglichkeit, die beiden Methoden mit wählbaren Attributen zu generieren. Eine Beispiel-Entität könnte dann wie folgt aussehen:
@Entity
public class Datensatz {

@Id @GeneratedValue
private Long id;

// weitere Felder, Getter, Setter, equals() etc. ...

/**
* Von Eclipse 3.5 generiert.
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((id == null) ? 0 : id.hashCode());
return result;
}
}
An sich liefert die Hashwert-Berechnung mittels Primzahlen eine gute Streuung, und der automatisch generierte Code beachtet auch, dass die Id null sein kann – nämlich bei noch nicht in der Datenbank gespeicherten (persistierten) Objekten.

Nun testen wir diese Entity-Klasse:
@Test
public void testAddToHashSet() {

Set<Datensatz> menge = new HashSet<Datensatz>();

Datensatz ds1 = new Datensatz();
Datensatz ds2 = new Datensatz();

assertTrue("Menge sollte leer sein", menge.isEmpty());

menge.add(ds1);

assertTrue("Menge sollte ein Element besitzen",
menge.size() == 1);
// ok

menge.add(ds2);

assertTrue("Menge sollte zwei Elemente besitzen",
menge.size() == 2);
// immer noch 1... Ups!?!
}
Immer, wenn man Assoziationen im Objekt-Modell aufbaut, bevor die Datensätze gespeichert sind (also z.B. bei Unit-Tests wie im obigen Beispiel), tritt das gezeigte Szenario auf. Wir haben hier zwei Objekte, die beide keine Id (=null) besitzen. Es sind aber trotzdem zwei nicht identische Objekte in separaten Speicherbereichen, die beim Persistieren entsprechend zwei Datensätze mit unterschiedlichen Primärschlüsseln (Ids) erzeugen würden. Leider kann sich das HashSet nur eines der beiden Objekte merken – und auch beim Persistieren einer Assoziation ginge so eines der Objekte verloren!

Eine Anpassung der generierten hashCode()-Methode ist denkbar einfach. Statt bei einer nicht vorhandenen Id die Zahl 0 für die Hashwert-Berechnung zu verwenden, nehmen wir den Hashwert des Objekts, der bei nicht identischen Objekten in den allermeisten Fällen unterschiedlich ist:
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((id == null) ? super.hashCode() : id.hashCode());
return result;
}
Eine vergleichbare Implementierung nutze ich seit Jahren ohne Probleme, weshalb ich diese Variante pauschal für die praktikabelste halte. In Einzelfällen mögen natürlich speziellere Implementierungen sinnvoller sein.

Mittwoch, 3. Februar 2010

HTML-Accesskey mit CSS darstellen

Mit dem Standard-HTML-Attribut accesskey lassen sich Tastaturkürzel (Shortcuts) definieren, mit denen man den Eingabefokus auf die zugehörigen Eingabeelemente setzen kann:
<label for="nachname" accesskey="n">Nachname:</label>
<input id="nachname" type="text">
Mit welcher Tastenkombination der Fokus gesetzt wird, ist browser- und systemabhängig. Obiges Kürzel aktiviert man im IE/Win mit Alt+N, im Firefox/Win mit Shift+Alt+N, im Firefox/Mac mit Ctrl+N, in Safari/Mac mit Ctrl+Alt+N...

Natürlich sollte man dem Anwender auch anzeigen, dass Tastaturkürzel vorhanden sind. Man kann diese Information zwar noch einmal statisch in den HTML-Quelltext schreiben (zusätzlich zum accesskey-Attribut). Mit einer einfachen CSS2-Regel kann man aber auf solche redundanten Angaben verzichten und die Kürzel an allen label-Elementen darstellen lassen, bei denen accesskey gesetzt ist:

label[accesskey]:after {
content: " [" attr(accesskey) "]";
text-transform: uppercase;
color: #999999;
font-size: x-small;
}

Die CSS-Regel basiert vor allem auf einem Attribut-Selektor und einem Pseudo-Element. Dadurch wird nach (:after) jedem label-Element, bei dem das accesskey-Attribut vorhanden ist, der Wert des Attributs in Großschreibung (uppercase) in den Dokument-Inhalt (content) eingefügt:



An sich sind diese Techniken recht alt, die entsprechenden Standards wurden schon vor Jahren offiziell verabschiedet (die HTML 4.01-Spezifikation ist über 10 Jahre alt, CSS 2 ebenso). Was macht dieses Thema wieder aktuell?

Google hat vor kurzem angekündigt, ab dem 1. März dieses Jahres ältere Browser-Versionen und insbesondere den Internet Explorer 6 (IE6) nicht mehr in seinen Web-Anwendungen zu unterstützen.
Dieser – eigentlich längst überfällige – Schritt dürfte auch andere Anbieter dazu bewegen, neuere IE-Versionen (oder Alternativen wie Firefox) vorauszusetzen. Und dann könnten auch endlich IE-Nutzer von Web-Standards wie den Attribut-Selektoren profitieren, die der IE6 leider seit Jahren ignoriert.

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.