Ein großer Schritt, von Version 4 auf 5. News unter http://www.theserverside.com/discussions/thread.tss?thread_id=79161. Im Kurs http://www.tutego.de/seminare/java-schulung/PrimeFaces-JSF2-Kurs.html gehen wir bald auch auf die Neuigkeiten ein.
Groovy 2.3.1 Update
Noch nicht lange die die Version 2.3 raus, jetzt schon kommt ein Update. Alle Infos unter http://jira.codehaus.org/secure/ReleaseNote.jspa?projectId=10242&version=20366.
gwtbootstrap3 Version 0.7 fertig
https://github.com/gwtbootstrap3 ist eine GWT-Bibliothek mit hübschen Komponenten, einen Grid-System, siehe dazu auch https://gwtbootstrap3.github.io/gwtbootstrap3-demo/, alles ist optimiert auf Umfluss für mobile Endgeräte. Es basiert auf Twitter Bootstrap http://getbootstrap.com/. Änderungen in Version 0.7:
- Added connivence methods to easily set margins/paddings on widgets.
- Ensured removal of all handlers on the unLoad of widgets
- Added methods to show/hide/toggle NavbarCollapse
- Further styled GWT’s CellTable/DataGrid to reflect Bootstrap tables
- Upped the dependency of GWT to 2.6.0
- Added submit/reset methods to Form
- Renamed all setTarget/setToggle methods to setDataTarget/setDataToggle, also any setter that referenced a data* attribute was renamed
- Added in a check as to not load jQuery if it’s already present
- Changed the parent of gwtbootstrap3-parent to oss-parent (org.sonatype.oss)
Was ich in meinem Code ändern musste war tatsächlich die *Data* Sache:
dismissButton.setDismiss( ButtonDismiss.MODAL ); –> dismissButton.setDataDismiss( ButtonDismiss.MODAL );
dialog.setKeyboard( true ); –> dialog.setDataKeyboard( true );
anchor.setTarget( "#" + title.hashCode() ); –> anchor.setDataTarget( "#" + title.hashCode() );
anchor.setToggle( Toggle.COLLAPSE ); –> anchor.setDataToggle( Toggle.COLLAPSE );
Eclipse 4.4.0 Release Candidate 1
Real Time Kommunikation mit Animated GIFs
Ein ziemlich intelligenter Trick, um Daten vom Server zum Client zu senden sind Animated GIFs. Ein GIF kann beliebig viele Frames haben und der Client hält die Verbindung offen um noch “den Rest” zu lesen.
https://github.com/videlalvaro/gifsockets ist eine JVM-Bibliothek in Java und Clojure, das genau das macht: Einen Server zu bauen, der Frame für Frame zum Client streamt. Es gibt ein Start-Frame, dann kann das Serverprogramm beliebig viele Frames senden und zum Schluss ein Abschluss-Frame – dafür gibt es eine API. Allerdings kodiert das Beispiel die Daten (hier Text) als Grafik “Graphics drawString()”; interessanter wäre es, Binärdaten über Farbwerte zu kodieren und auf dem Client dann auszulesen – hier ist also noch Platz für ein weiteres Open-Source-Projekt.
Natürlich brauch so etwas nicht wirklich, wenn man WebSockets nutzen kann. Doch es ist ein interessanter Hack.
Eclipse 4.4 M7 (Luna)
http://download.eclipse.org/eclipse/downloads/drops4/S-4.4M7-201405010200/news/
Für mich ist wichtig:
Java 8: Java™ 8 is here, and JDT fully supports it:
- The Eclipse compiler for Java (ECJ) implements all the new Java 8 language enhancements
- Updated significant features to support Java 8, such as Search and Refactoring
- New formatter options for lambdas
- Quick Assist and Clean Up to migrate anonymous class creations to lambda expressions and back:
Before:
After the Quick Assist (Ctrl+1), the 6 lines are condensed into 1:
Heute kommt auch der erste Release Candidate (RC) raus.
Inselraus: JDBC Metadaten
Von einer Datenbank können verschiedene Informationen ausgelesen werden. Zum einen sind dies Informationen zu einer bestimmten Tabelle, zum anderen Informationen über die Datenbank selbst.
Metadaten über die Tabelle
Bei der Abfrage über alle Spalten müssen wir die Struktur der Datenbank kennen, insbesondere dann, wenn wir allgemeine Abfragen vornehmen und die passenden Daten herauslesen wollen. So liefert SELECT * FROM Item ein ResultSet mit der Anzahl der Spalten, wie sie die Tabelle Item hat. Doch bevor wir nicht die Anzahl und die Art der Spalten kennen, können wir nicht auf die Daten zugreifen.
Um diese Art von Informationen, so genannte Metadaten, in Erfahrung zu bringen, befindet sich die Klasse ResultSetMetaData, mit der wir diese Informationen erhalten, unter den SQL-Klassen. Metadaten können für jede Abfrage angefordert werden. So lässt sich unter anderem leicht herausfinden:
- wie viele Spalten wir in einer Zeile abfragen können
- wie der Name der Spalte lautet
- welchen SQL-Typ die Spalte hat
- ob NULL für eine Spalte in Ordnung ist
- wie viele Dezimalzeichen eine Spalte hat
Einige Informationen über die Bestellelemente
Um Anzahl und Art der Spalten einer Bestelltabelle herauszufinden, werden wir zunächst ein ResultSet mit stmt.executeQuery(„SELECT * FROM Item“) erzeugen und dann via getMetaData() ein ResultSetMetaData-Objekt erfragen. Das ResultSetMetaData-Objekt besitzt viele Methoden, um Aussagen über die Tabelle und die Spalten zu treffen. So fragen wir mit getColumnCount() nach, wie viele Spalten die Tabelle hat. Anschließend lässt sich für jede Spalte der Name und Typ erfragen:
String url = "jdbc:hsqldb:file:TutegoDB;shutdown=true";
String sql = "SELECT * FROM ITEM";
try ( Connection con = DriverManager.getConnection( url, "sa", "" );
Statement stmt = con.createStatement();
ResultSet rs = con.createStatement().executeQuery( sql ) ) {
ResultSetMetaData meta = rs.getMetaData();
int numerics = 0;
for ( int i = 1; i <= meta.getColumnCount(); i++ ) {
System.out.printf( "%-20s %-20s%n", meta.getColumnLabel( i ),
meta.getColumnTypeName( i ) );
if ( meta.isSigned( i ) )
numerics++;
}
System.out.println();
System.out.println( "Spalten: " + meta.getColumnCount() +
", Numerisch: " + numerics );
}
interface java.sql.ResultSet
extends Wrapper, AutoCloseable
- ResultSetMetaDatagetMetaData()throwsSQLException
Liefert die Eigenschaften eines ResultSet in einem ResultSetMetaData zurück.
interface java.sql.ResultSetMetaData
extends Wrapper
- intgetColumnCount()
Liefert die Anzahl der Spalten im aktuellen ResultSet. Das ist praktisch für SQL-Anweisungen wie SELECT *.
Allen folgenden Methoden wird ein int übergeben, das die Spalte kennzeichnet:
- StringgetCatalogName(intcolumn)
Gibt den String mit dem Katalognamen der Tabelle für die angegebene Spalte zurück. - StringgetColumnName(intcolumn)
Liefert den Spaltennamen der Tabelle. - intgetColumnDisplaySize(intcolumn)
Maximale Anzahl der Zeichen, die die Spalte einnimmt. So ist bei einer Spalte vom Typ VARCHAR(11) mit einer maximalen Spaltenbreite von zehn Zeichen zu rechnen. Bei numerischen Spalten variiert der Wert. - StringgetColumnLabel(intcolumn)
Gibt einen String zurück, der den Titel der angegebenen Spalte enthält. Der Titel gibt an, welche Überschrift für die Spalte angezeigt werden soll. Einige Datenbanken erlauben die Unterscheidung zwischen Spaltennamen und Spaltentitel. - intgetColumnType(intcolumn)
Der Typ der Spalte wird ermittelt. Der Spaltentyp ist dabei eine Konstante aus der Klasse java.sql.Types. Sie deklariert Konstanten nach dem XOPEN-Standard. Dazu zählen unter anderem BIGINT, BINARY, BIT, BLOB_LOCATOR, CHAR, CLOB_LOCATOR, DATE, DECIMAL, DISTINCT, DOUBLE, FLOAT, INTEGER, JAVA_OBJECT (benutzerdefinierter Datentyp), STRUCT, TIME, TIMESTAMP, TINYINT, VARBINARY, VARCHAR. Die Konstante OTHER zeigt ein datenbankspezifisches Element an und wird auf ein Java-Objekt abgebildet, falls ein Zugriff mittels getObject(…) oder setObject(…) erfolgt. - StringgetColumnTypeName(intcolumn)
Liefert den Namen der Spalte, so wie sie die Datenbank definiert. - intgetPrecision(intcolumn)
Liefert die Dezimalgenauigkeit der Spalte, zurückgegeben als Anzahl der Ziffern. - intgetScale(intcolumn)
Liefert die Genauigkeit der Spalte. Dies ist die Anzahl der Stellen, die nach dem Dezimalpunkt verwendet werden können. - StringgetSchemaName(intcolumn)
Der Name des Tabellenschemas. Wird von den Methoden des DatabaseMetaData-Objekts benutzt. Falls kein Schema vorhanden ist, wird „“ zurückgegeben. - StringgetTableName(intcolumn)
Liefert den Tabellennamen der angegebenen Spalte. - booleanisAutoIncrement(intcolumn)
Stellt fest, ob eine Spalte eine Auto-Increment-Spalte ist. Diese nimmt dann automatisch den nächsten freien Wert an, wenn ein neuer Datensatz eingefügt wird. Ist die erste Zeile einer Tabelle mit einer Auto-Increment-Spalte eingefügt, so nimmt die Spalte den Wert 1 an. In den meisten Datenbanken ist es allerdings nicht möglich, eigene Werte in diesen Spalten einzutragen. - booleanisCaseSensitive(intcolumn)
Berücksichtigt die Spalte die Groß- bzw. Kleinschreibung? - booleanisCurrency(intcolumn)
Enthält die Spalte Geldwerte? Nur einige Datenbanken bieten diesen Spaltentyp. - booleanisNullable(intcolumn)
Ist ein SQL-NULL in der Spalte erlaubt? - booleanisSearchable(intcolumn)
Kann die Spalte in einer SQL-WHERE-Klausel verwendet werden? - booleanisSigned(intcolumn)
Enthält die Spalte vorzeichenbehaftete Datentypen? Vorzeichenbehaftete Typen sind unter anderem INT, LONGINT und SMALLINT. Vorzeichenlose Typen sind unter anderem UINT, ULONG und UBYTE. - booleanisReadOnly(intcolumn)
Ist es möglich, auf die Spalte definitiv nicht schreibend zuzugreifen? Ist das Ergebnis true, kann der Wert also nicht aktualisiert werden. - booleanisWritable(intcolumn)
Ist es prinzipiell möglich, auf die Spalte schreibend zuzugreifen? Häufig wird das als !isReadOnly(column) implementiert. - booleanisDefinitelyWritable(intcolumn)
Kann auf die Spalte definitiv schreibend zugegriffen werden? Viele Datenbanken liefern die gleichen Ergebnisse bei isDefinitelyWritable(…) und isWritable(…). Prinzipiell könnte der Zustand von isWritable(…) abweichen, wenn sich zum Beispiel die Schreibbarkeit dynamisch ändert.
Alle Methoden können eine SQLException auslösen.
Informationen über die Datenbank
Metadaten sind auch für die gesamte Datenbank abfragbar. Beispiele für diese Informationen sind:
- Welche Tabellen liegen in der Datenbank?
- Wer ist mit der Datenbank verbunden?
- Kann die Datenbank nur gelesen oder kann auch in die Datenbank geschrieben werden?
- Wie lauten die Primärschlüssel für eine Tabelle?
- Sind gespeicherte Prozeduren auf der Datenbankseite erlaubt?
- Lassen sich äußere Joins (outer joins) durchführen?
Sind Informationen über die Datenbank gefragt, so lassen sich über Metadaten eines DatabaseMetaData-Objekts beispielsweise Datenbankeigenschaften des Herstellers herausfinden. Zunächst benötigen wir dazu ein DatabaseMetaData-Objekt, das uns getMetaData() von einer Connection gibt. Das DatabaseMetaData-Objekt deklariert eine große Anzahl Methoden:
DatabaseMetaData meta = con.getMetaData(); System.out.println( "Product name " + meta.getDatabaseProductName() ); System.out.println( "Version: " + meta.getDatabaseProductVersion() ); System.out.println( "Maximum number of connections: " + meta.getMaxConnections() ); System.out.println( "JDBC driver version: " + meta.getDriverVersion() ); System.out.println( "Supports update in batch: " + meta.supportsBatchUpdates() ); System.out.println( "Supports stored procedures: " + meta.supportsStoredProcedures() );
Inselraus: Groovy
Groovy (http://groovy.codehaus.org/) ist eine objektorientierte Skriptsprache, die auf einer JVM läuft und vollen Zugriff auf alle Java-Bibliotheken bietet. Die Sprache hat viele interessante Eigenschaften, die sie zu Java X machen. Groovy setzt auf der Standard-Java-Syntax auf und erweitert diese.[1] Einige Höhepunkte:
Groovy-Feature | Beispiel |
Statt System.out.print(…)/println(…) reicht ein print bzw. println, und dann muss das Argument auch nicht in runden Klammern stehen. | println 1 + 2 print „Wow“ |
Anweisungen müssen nicht immer mit einem Semikolon abgeschlossen werden, sondern nur dann, wenn mehrere Anweisungen in einer Zeile stehen. | print „Wow“ print „Wow“; print „Wow“ |
Variablen müssen nicht mit einem Typ deklariert werden, das gilt auch bei catch oder Methoden/Konstruktoren. | def age = 40 def greet( name ) { print „Hallo “ + name } try { } catch ( e ) { } |
Zeichenketten lassen sich mit einfachen oder doppelten Anführungszeichen angeben. Einzelne Zeichen (char/Character) müssen besonders aufgebaut werden. | print „Ja“ == ‚Ja‘ // true def sign = „-“ as char |
Strings in doppelten Anführungszeichen sind besondere GStrings: Enthalten sie $variable bzw. ${ausdruck}, so wird der Inhalt der Variablen bzw. der ausgewertete Ausdruck eingesetzt. | def one = 1 print „$one plus $one macht ${1+1}“ // 1 plus 1 macht 2 |
Strings können über mehrere Zeilen laufen, wenn sie in „““ oder “‘ eingeschlossen sind – folgt ein Backslash am Ende der Zeile, wird kein Zeilenumbruchzeichen eingefügt. | print „““ Zeile 1 Zeile 2\ Weiter mit Zeile 2 „““ |
Alles ungleich 0 und null ist true. | if ( 1 ) print ‚Zweig wird genommen‘ |
Groovy definiert einen neuen Datentyp für Bereiche (engl. ranges). | def numbers1 = 0..9 def numbers2 = 0..<10 |
Erweiterte Zählschleife unter Berücksichtigung von Bereichen, bzw. rechts von in steht ein Iterable wie beim erweiterten for. | for ( i in 0..<10 ) print i // 0123456789 |
== bei Referenzen bedeutet equals(…)-gleich; ein Identitätsvergleich realisiert is(…). | def heinz = ‚Heinz‘ print heinz == ‚Heinz‘ // true |
Operatoren können überladen werden, und die Anwendung von Operatoren entspricht Methodenaufrufen, etwa + von plus(…), ++ von next(…) oder [] von getAt(…). | println 1 + 2 * 3 // 7 println 1.plus(2).multiply(3) // 9 println 1.plus(2.multiply(3)) // 7 |
Alle Comparable-Objekte (und damit etwa String, BigInteger, BigDecimal) können mit ==, !=, <, >, <= und >= verglichen werden. Die Ordnung liefert compareTo(…). | def heinz = ‚Heinz‘ print heinz < ‚Werner‘ // true |
Ist in Java nur java.lang standardmäßig importiert, ist es bei Groovy viel mehr, etwa noch java.io, java.util, java.net und noch einige. | print new File(‚file.txt‘).exists() |
Statt explizit auf Datenstrukturklassen für Listen und Mengen zurückzugreifen, bietet Groovy eine spezielle Syntax. | def primes = [ 2, 3, 5, 7] print primes[ 0 ] def dic = [ ‚rot‘ : ‚red‘, ‚blau‘ : ‚blue‘ ] print dic[‚rot‘] // red |
Die Operatoren ?. und ?: (Elvis-Operator) verhindern null-Zugriffe. | def name = ‚Chris‘ println name ?: ‚Kein Name‘ // Chris name = null println name ?: ‚Kein Name‘ // Kein Name |
Der Zugriff auf Zeichen über [] ist bei den Zeichenkettenklassen String, StringBuffer, StringBuilder möglich. | def s = ‚Ooog‘ print s[0] // O |
Der Zugriff über [] lässt auch Bereiche zu. | def s = „tutego“ print s[ 0, 1, 3..5 ] // tugeo def t = new StringBuilder( „tutego“ ) t[ 1..4 ] = „X“ print t // tXo |
Der Operator << hängt Dinge an Strings (Rückgabe ist dann StringBuffer), Listen oder Dateien an. | def s = ‚oger‘ def sb = ‚Das ist ‚ << s << ‚ oder?‘ print sb // Das ist oger oder? def file = new File(„out.txt“) file << „Zeile 1“ |
Reguläre Ausdrücke werden mit einer eigenen Syntax direkt von der Sprache unterstützt; =~ ist ein find, ==~ ein match. | print ‚2010‘ ==~ /\d+/ |
erweitertes switch-case etwa mit regulären Ausdrücken und Bereichen | switch ( 42 ) { case 0..100 : println ‚ist zwischen 0..100‘; break case Integer : println ‚ist Integer‘; break case { it % 2 == 0 }: println ‚ist gerade‘; break case ~/\d\d/: println ’42 passt auf das Pattern‘; break } |
Datentyp für Dauer und spezielle Eigenschaften für Datumswerte und überladene Operatoren zum leichten Rechnen mit dem Paket groovy.time | use ( groovy.time.TimeCategory ) { def today = new Date() def tomorrow = today + 1.day print „Morgen: $tomorrow, nächstes Jahr ${today + 1.year}“ } |
Closures als Codeblöcke werden unterstützt und finden überall in der Groovy-API Anwendung. | new File( „file.txt“ ).eachLine { println it } def names = [ „Charisma“, “ „, „Tina“, „“ ] print names.findAll { ! it.trim().isEmpty() } // [Charisma, Tina] |
Setter/Getter müssen nicht aufgerufen werden; beim Zugriff ref.property wird automatisch der Setter/Getter aufgerufen. | def p = new Point( 10, 20 ) print p.location.x // 10.0 |
In Methoden mit Rückgabe kann das Schlüsselwort return entfallen. | def add( a, b ) { a + b } |
Default-Parameter bei Methodendeklarationen | static tax( cost, taxRate = 19 ) { cost * taxRate / 100 } println tax( 100 ) // 19 println tax( 100, 7 ) // 7 |
Methoden und Klassen sind standardmäßig public, nicht paketsichtbar wie bei Java. Groovy erstellt automatisch Setter/Getter. | class Person { def name } |
Mit der Klassenannotation @Immutable wird ein Typ unveränderbar, mit @Singleton ein Singleton mit einem privaten Konstruktor und öffentlichem Attribut instance für die eine Instanz. | @Immutable class Pair { String val1, val2 } @Singleton class AppWindow { } |
Diverse Builder-Klassen erleichtern den Aufbau von hierarchischen XML- oder Swing-Bäumen ebenso wie Ant-Build-Skripten. | import groovy.xml.MarkupBuilder def writer = new StringWriter() new MarkupBuilder( writer ).html { head { title ‚Zählen mit Graf Zahl‘ } body { h1 ( ‚Willkommen‘ ) p { ul { (1..10).each { li it } } a( href:“’http://stupidedia.org/stupi/Graf_Zahl“‘, ‚Graf Zahl‘ ) } } } println writer |
Eigenschaften von Groovy mit Beispiel
Groovy-Skripte in Eclipse ausführen
Um Groovy-Skripte und Programme auszuführen, bieten sich drei Wege an:
- über eine spezielle Kommandozeile, die Groovy-Shell
- über das Eclipse-Plugin
- über die javax.script-API
Das Eclipse-Plugin unter http://groovy.codehaus.org/Eclipse+Plugin leistet gute Arbeit und wird ständig weiterentwickelt. Auf der Webseite ist der Update-Link genannt, sodass Groovy-Eclipse über den Update-Manager installiert werden kann.
- Wähle dazu Eclipse Help • Install New Software…
- In der Dialogbox fülle das Textfeld bei Work with mit dem Link http://dist.springsource.org/release/GRECLIPSE/e4.3/ (bzw. anderen Versionen je nach Eclipse-Version), und aktiviere Add…
- Aktiviere anschließend Groovy-Eclipse, und führe die Installation mit Next usw. zu Ende.
Ist Eclipse neu gestartet und das Plugin installiert, kann jedes Java-Projekt um Groovy-Unterstützung erweitert werden. Bei einem Java-Projekt aktiviert die Aktion Configure • Convert to Groovy Project im Kontextmenü genau diese Groovy-Unterstützung, sodass im Projektbaum die Groovy-Bibliotheken auftauchen.
File • New • Other… ermöglicht zum einen im Zweig Groovy das Erstellen eines neuen Groovy-Projekts (durch die Konvertierung eines existierenden Java-Projekts ist das nicht mehr nötig) und zum anderen mit Groovy Class das Erstellen einer Groovy-Klasse. Bei dieser Option lässt sich ein Paket- und Klassenname eingeben (etwa com.tutego.insel.script und GroovyBabe), und dann öffnet Eclipse den Groovy-Editor.
Löschen wir die Klassendeklaration und setzen nur die zwei Zeilen in die Datei:
package com.tutego.insel.script
print „Hallo Groovy“
Ausgeführt wird das Groovy-Skript im Kontextmenü (oder Run-Menü) mit Run As • Groovy Skript.
Groovy über die Skript-API ausführen
Um Groovy als Skriptsprache aus einem Java-Programm heraus zu nutzen, können wir wieder auf die Skript-API zurückgreifen. Wenn es sich bei Eclipse schon um ein Groovy-Projekt handelt, ist ein JAR schon im Klassenpfad eingebunden, und es ist nichts zu tun. Andernfalls bekommen wir von der Webseite http://groovy.codehaus.org/Download unter Download zip: Binary Release ein fast 30 MiB großes ZIP-Archiv wie groovy-binary-2.2.2.zip, wo groovy-all-2.2.2.jar im Ordner embeddable liegt und das wir in den Klassenpfad mit aufnehmen.
Ein kleines Beispiel:
ScriptEngine engine = new ScriptEngineManager().getEngineByName( "groovy" );
System.out.println( engine.eval( "(1g..42g.gcd(56g)).sum()" ) ); // 105
[1] Bis auf sehr kleine Ausnahmen ist jedes Java-Programm ein Groovy-Programm.
Inselraus: Zeitdauern und der XML-Datentyp Duration
Eine der Schwachstellen in der Datumsverarbeitung ist das Fehlen eines Typs für Dauern (wenn wir von TimeUnit einmal absehen). Ein eigenständiger Typ bringt Vorteile, wenn es zum Beispiel darum geht, Dauern zu addieren (»Was ergibt 1 Woche plus 2 Monate?«) oder zu vergleichen (»Ist 1 Stunde mehr als 123456789 Millisekunden?«). Zwar lassen sich mit der add(…)-Methode von Calendar einzelne Segmente ändern, und dadurch lässt sich ein früherer oder späterer Zeitpunkt ansteuern, aber das ist wenig objektorientiert. Besser ist ein eigener Datentyp, der auch Operationen anbietet, um die Dauer auf ein Calendar- oder Date-Objekt zu setzen.
DatatypeFactory als Fabrik
Im Rahmen der W3C-XML-Schema-Unterstützung gibt es Klassen, unter anderem den Typ Duration für Dauern nach der gregorianischen Zeit. Die Klasse liegt jedoch nicht im java.util-Paket, sondern wegen ihres XML-Bezugs im Paket javax.xml.datatype (wo es neben XMLGregorianCalendar nahezu alleine liegt). Exemplare von Duration werden auch von keinem Konstruktor angelegt, sondern von einer Fabrikklasse DatatypeFactory. Beispiel: Lege ein Duration-Objekt mit der Dauer von 1 Tag und 2 Stunden an:
Duration d = DatatypeFactory.newInstance().newDuration(true, 0, 0, 1, 2, 0, 0 ); System.out.println( d ); // P0Y0M1DT1H0M0S
Die DatatypeFactory bietet diverse Fabrikmethoden zum Anlegen der Duration-Objekte. Die Parameterlisten sind wie im Beispiel mitunter recht lang – in der längsten Variante gibt es einen Indikator für ein Vorzeichen, Jahr, Monat, Tag, Stunden, Minuten, Sekunden (keine Millisekunden oder genauer), also mit sieben Parametern. Ein Builder-Pattern zum Aufbau der Objekte wäre nett gewesen … abstract class javax.xml.datatype.DatatypeFactory
- staticDatatypeFactorynewInstance()throwsDatatypeConfigurationException
- DurationnewDuration(booleanisPositive,intyears,intmonths,intdays,inthours, intminutes,intseconds)
- abstractDurationnewDuration(booleanisPositive,BigIntegeryears,BigIntegermonths, BigIntegerdays,BigIntegerhours,BigIntegerminutes,BigDecimalseconds)
- abstractDurationnewDuration(longdurationInMilliSeconds)
- abstractDurationnewDuration(StringlexicalRepresentation)
- DurationnewDurationDayTime(booleanisPositive,BigIntegerday,BigIntegerhour,BigInteger minute,BigIntegersecond)
- DurationnewDurationDayTime(booleanisPositive,intday,inthour,intminute,intsecond)
- DurationnewDurationDayTime(longdurationInMilliseconds)
- DurationnewDurationDayTime(StringlexicalRepresentation)
- DurationnewDurationYearMonth(booleanisPositive,BigIntegeryear,BigIntegermonth)
- DurationnewDurationYearMonth(booleanisPositive,intyear,intmonth)
- DurationnewDurationYearMonth(longdurationInMilliseconds)
- DurationnewDurationYearMonth(StringlexicalRepresentation)
Die Duration-Klasse und ihre Methoden
Die Duration-Ausgabe im Beispiel über toString() liefert eine besondere String-Repräsentation, die für XML-Dokumente interessant ist, aber andere Methoden sind interessanter. Eine grobe Einteilung ergibt:
- Anfragemethoden für die Segmente wie getYear(), getDay(), …
- Vergleichsmethoden wie compare(Duration) oder isLongerThan(Duration)
- Duration-Objekte sind immutable, doch gibt es Methoden wie add(Duration) oder multiply(Duration), die neue Duration-Objekte mit veränderten Segmenten zurückgeben, oder die Methode normalizeWith(Calendar), die Calendar-Felder zur Initialisierung nutzt.
- Anwenden der Duration-Objekte auf Calendar oder Date mit addTo(Calendar)/ addTo(Date).
Beispiel: Addiere die Dauer von 2 Monaten und 3 Tagen, und berechne, wo wir dann relativ zu heute stehen:
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance(); Duration d1 = datatypeFactory.newDurationYearMonth( true, 0, 2 ); Duration d2 = datatypeFactory.newDuration( true, 0, 0, 3, 0, 0, 0 ); Duration sum = d1.add( d2 ); Date date = new Date(); System.out.printf( "%tF%n", date ); // 2011-06-21 sum.addTo( date ); System.out.printf( "%tF%n", date ); // 2011-08-24
Mögliche und unmögliche Operationen
Intern speichert die Duration-Implementierung jedes einzelne Segment und legt es nicht zu einer Zahl, etwa Sekunden zusammen. Das wäre auch nicht möglich, da die Anzahl Tage im Monat und im Jahr nicht immer gleich sind (dass zeigen uns der Februar und Schaltjahre). Wenn wir auf dem 1.1. einen Monat addieren, wollen wir beim 1.2. auskommen, und wenn wir bei 1.2. beginnen und einen Monat addieren, soll der 1.3. das Ergebnis sein. Beispiel: Additionen eines Monats auf einen Kalender:
DatatypeFactory datatypeFactory = DatatypeFactory.newInstance(); Duration month = datatypeFactory.newDurationYearMonth( true, 0, 1 ); Calendar cal = new GregorianCalendar( 2012, Calendar.JANUARY, 1 ); month.addTo( cal ); System.out.printf( "%tF%n", cal); // 2012-02-01 month.addTo( cal ); System.out.printf( "%tF%n", cal); // 2012-03-01
Da die Anzahl der Tage im Monat und im Jahr beweglich ist, sind bei add(…) und substract(…) nur gewisse Kombinationen möglich. Es gibt Operationen, die Duration nicht ausführen kann und mit einer IllegalStateException bestraft. Während innerhalb der Gruppe Sekunden, Minuten, Stunden und Tage beliebig addiert und subtrahiert werden können, ist der Übergang nach Monat und Jahr problematisch, insbesondere bei Subtraktionen. Beispiel: 1 Monat minus 1 Tag ist genauso wenig möglich wie 1 Jahr minus 1 Tag:
DatatypeFactory factory = DatatypeFactory.newInstance(); Duration year = factory.newDuration( true, 1, 0, 0, 0, 0, 0 ); Duration month = factory.newDuration( true, 0, 1, 0, 0, 0, 0 ); Duration day = factory.newDuration( true, 0, 0, 1, 0, 0, 0 ); year.subtract( day ); // N IllegalStateException month.subtract( day ); // N IllegalStateException
Duration-Vergleiche
Beim Vergleichen zweier Dauern gibt es vier unterschiedliche Ergebnisse, und daher implementiert Duration auch nicht die bekannte Comparable-Schnittstelle. Der Grund ist, dass einige Vergleiche nicht endscheidbar sind. So sind 30 Tage sind nicht automatisch 1 Monat, 365 Tage nicht automatisch 1 Jahr. Die compare(…)-Methode liefert Ganzahlen, die den jeweiligen Ausgang dokumentieren:
Vergleichsergebnis | Beispiel | Konstante |
Dauer1 ist kürzer als Dauer2. | 1 Minute ist kürzer als 100 Sekunden | DatatypeConstants.LESSER |
Dauer1 ist länger als Dauer2. | 1 Tag ist länger als 1 Minute | DatatypeConstants.GREATER |
Dauer1 ist gleichlang Dauer2. | 1 Minute ist gleich 60 Sekunden | DatatypeConstants.EQUAL |
Dauer1 ist unvergleichbar mit Dauer2. | 30 Tage sind nicht automatisch 1 Monat | DatatypeConstants.INDETERMINATE |
Ausgang von Vergleichen zwischen Duration-Objekten Beispiel: Vergleiche 30 Tage mit 1 Monat:
DatatypeFactory factory = DatatypeFactory.newInstance(); Duration month = factory.newDurationYearMonth( true, 0, 1 ); Duration thirtyDays = factory.newDuration( true, 0, 0, 30, 0, 0, 0 ); System.out.println( month.compare( thirtyDays ) == DatatypeConstants.INDETERMINATE ); // true System.out.println( month.isLongerThan( thirtyDays ) ); // false System.out.println( thirtyDays.isLongerThan( month ) ); // false
Wir sprechen bei Duration daher auch nur von einer partiellen Ordnung statt von einer vollständigen Ordnung.
Zusammenfassung der Duration-Methoden
abstract class javax.xml.datatype.DatatypeFactory
- abstractintgetSign()
- intgetYears()
- intgetMonths()
- intgetDays()
- intgetHours()
- intgetMinutes()
- intgetSeconds()
- abstractDurationadd(Durationrhs)
- Durationsubtract(Durationrhs)
- Durationmultiply(intfactor)
- abstractDurationmultiply(BigDecimalfactor)
- abstractDurationnegate()
- abstractintcompare(Durationduration)
- booleanisLongerThan(Durationduration)
- booleanisShorterThan(Durationduration)
- abstractvoidaddTo(Calendarcalendar)
- voidaddTo(Datedate)
- abstractDurationnormalizeWith(CalendarstartTimeInstant)
- longgetTimeInMillis(CalendarstartInstant)
- longgetTimeInMillis(DatestartInstant)
- abstractbooleanisSet(DatatypeConstants.Fieldfield)
- abstractNumbergetField(DatatypeConstants.Fieldfield)
- QNamegetXMLSchemaType()
- abstractinthashCode()
- booleanequals(Objectduration)
- StringtoString()
Seit dem in Java 8 die Java Date & Time API eingezogen ist, muss man nicht mehr zu diesen Typen greifen, es sei denn, mann arbeitet direkt mit der XML-API.
Vertragen sich Oracle und Apache?
Java Grundlagen-Seminar vom 23.06. bis 27.06. in Dortmund
Erstes offenes Seminar in Dortmund, weitere Seminarorte und Termine folgen.
Inhalte und Details: http://www.tutego.de/seminare/java-schulung/java-einfuehrung-seminar-java-1-grundlagen-schulung-java-einsteiger-kurs.html
Trainer voraussichtlich: Christian Ullenboom
Mehrere Monitore mit ScreenFX ansteuern
Die quelloffene Bibliothek ScreenFX bringt Stages auf unterschiedliche Monitore und kümmert sich um die korrekten Größenänderungen usw.
Tastaturcodes lassen sich für die Umschaltung definieren. Standardmäßig ist die Bibliothek mit Java 8 kompiliert.
Weitere FX-Komponenten unter http://www.tutego.de/java/javafx-komponenten.htm.
RichTextFX (GPLv2 with the Classpath Exception)
Seit JavaFX 8 kann JavaFX dank TextFlow problemlos Text mit unterschiedlichen Formatierungen anzeigen. RichTextFX (ehemals CodeAreaFX) greift darauf zurück und bietet mit StyleClassedTextArea
eine Komponente, bei der einfach gewisse Teile vom Text ausgezeichnet werden können. Ein kleiner Editor kommt als Demo mit:
Weiterhin gibt es eine vorgefertigte Editor-Komponente an, die als Basis für eigene Code-Editoren dienen kann:
Über Code oder CSS lässt sich die Darstellung ändern.
Weiter FX-Komponenten unter http://www.tutego.de/java/javafx-komponenten.htm.
ReactFX (https://github.com/TomasMikula/ReactFX)
Thomas Mikula fasst die JavaFX 8 Bibliothek ReactFX mit den Worten "Reactive event streams, inhibitable bindings and more for JavaFX" zusammen. Die Bibliothek veröffentlicht spezifische Ereignisse einer JavaFX-Anwendung auf einer Art lokalen Bus (Typ EventStream
) und erlaubt es auf der anderen Seite Klienten an diesem EventStream
Bus zu lauschen. Geht es zum Beispiel darum Maus-Klicks auf einem Knoten zu registrieren und dann bei Klicks Code auszuführen sieht es im Code so aus:
EventStream<MouseEvent> clicks = EventStreams.eventsOf( node, MouseEvent.MOUSE_CLICKED ); clicks.subscribe( click -> System.out.println("Klick!") );
So gesehen bietet die API noch keinen Vorteil, spannend wird es, wenn der EventStream
gefiltert, mit anderen EventStream
s verschmolzen oder die Ereignisse gemappt werden — die Programmierung erinnert an die neue Stream-API aus Java 8.
Weitere FX-Komponenten unter http://www.tutego.de/java/javafx-komponenten.htm.
tutego bietet auch ein JavaFX-Seminar an: http://www.tutego.de/seminare/java-schulung/JavaFX-Seminar-JavaFX-Script-Kurs.html
Funktionale Schnittstelle in Java 8 aus java.util.function
Funktionen realisieren Abbildungen und da es verschiedene Arten von Abbildungen geben kann, bietet die Java Standardbibliothek im Paket java.util.function für die häufigsten Fälle funktionale Schnittstellen an. Ein erster Überblick:
Schnittstelle | Abbildung |
Consumer<T> | (T) → void |
DoubleConsumer | (double) → void |
BiConsumer<T, U> | (T, U) → void |
Supplier<T> | () → T |
BooleanSupplier | () → boolean |
Predicate<T> | (T) → boolean |
LongPredicate | (long) → boolean |
BiPredicate<T, U> | (T, U) → boolean |
Function<T, R> | (T) → R |
LongToDoubleFunction | (long) → double |
BiFunction<T, U, R> | (T, U) → R |
UnaryOperator<T> | (T) → T |
DoubleBinaryOperator | (double) → boolean |
Beispiele einiger vordefinierter funktionaler Schnittstellen
Weiterlesen
Thema der Woche: Java Mission Control
1. Schaue folgendes Video:
2. Spiele das gemachte Beispiele (aus LinkedList wird HashSet und das Boxing wird entfernt) an einem eigenen Beispiel nach.
jdeps Kommandozeilentool in Java 8
Das JDK bringt mit jdeps ein kleines statisches Analysewerkzeug mit, welches die statischen Abhängigkeiten eines Java-Programms aufzeigt. Dabei listet es alle referenzierten Pakete auf und optional noch die Profile.
$ jdeps
Usage: jdeps <options> <classes…>
where <classes> can be a pathname to a .class file, a directory, a JAR file,
or a fully-qualified class name. Possible options include:
-dotoutput <dir> Destination directory for DOT file output
-s -summary Print dependency summary only
-v -verbose Print all class level dependencies
-verbose:package Print package-level dependencies excluding
dependencies within the same archive
-verbose:class Print class-level dependencies excluding
dependencies within the same archive
-cp <path> -classpath <path> Specify where to find class files
-p <pkgname> -package <pkgname> Finds dependences in the given package
(may be given multiple times)
-e <regex> -regex <regex> Finds dependences in packages matching pattern
(-p and -e are exclusive)
-include <regex> Restrict analysis to classes matching pattern
This option filters the list of classes to
be analyzed. It can be used together with
-p and -e which apply pattern to the dependences
-P -profile Show profile or the file containing a package
-apionly Restrict analysis to APIs i.e. dependences
from the signature of public and protected
members of public classes including field
type, method parameter types, returned type,
checked exception types etc
-R -recursive Recursively traverse all dependencies
-jdkinternals Finds class-level dependences on JDK internal APIs.
By default, it analyzes all classes on -classpath
and input files unless -include option is specified.
This option cannot be used with -p, -e and -s options.
WARNING: JDK internal APIs may not be accessible in
the next release.
-version Version information
Ein Beispiel:
$ jdeps "c:\Program Files\Java\jdk1.8.0\lib\ant-javafx.jar"
c:\Program Files\Java\jdk1.8.0\lib\ant-javafx.jar -> c:\Program Files\Java\jdk1.8.0\jre\lib\rt.jar
c:\Program Files\Java\jdk1.8.0\lib\ant-javafx.jar -> not found
com.javafx.main (ant-javafx.jar)
-> java.applet
-> java.awt
-> java.awt.event
-> java.io
-> java.lang
-> java.lang.reflect
-> java.net
-> java.security
-> java.util
-> java.util.jar
-> javax.swing
-> sun.misc JDK internal API (rt.jar)
com.sun.javafx.tools.ant (ant-javafx.jar)
-> java.io
-> java.lang
-> java.security.cert
-> java.util
-> java.util.jar
-> java.util.zip
-> org.apache.tools.ant not found
-> org.apache.tools.ant.taskdefs not found
-> org.apache.tools.ant.types not found
-> org.apache.tools.ant.types.resources not found
-> sun.misc JDK internal API (rt.jar)
com.sun.javafx.tools.packager (ant-javafx.jar)
-> java.io
-> java.lang
-> java.lang.reflect
-> java.math
-> java.net
-> java.nio.file
-> java.security
-> java.security.cert
-> java.text
-> java.util
-> java.util.jar
-> java.util.regex
-> java.util.zip
-> sun.misc JDK internal API (rt.jar)
-> sun.security.pkcs JDK internal API (rt.jar)
-> sun.security.timestamp JDK internal API (rt.jar)
-> sun.security.util JDK internal API (rt.jar)
-> sun.security.x509 JDK internal API (rt.jar)
com.sun.javafx.tools.packager.bundlers (ant-javafx.jar)
-> java.io
…
Funktionale Programmierung mit Java
Programmierparadigmen: imperativ oder deklarativ
In irgendeiner Weise muss ein Entwickler sein Problem in Programmform beschreiben, damit der Computer es letztendlich ausführen kann. Hier gibt es verschiedene Beschreibungsformen, die wir Programmierparadigmen nennen. Bisher haben wir uns immer mit der imperativen Programmierung beschäftigt, bei der Anweisungen im Mittelpunkt stehen. Wir haben im Deutschen den Imperativ, also die Befehlsform, die sehr gut mit dem Programmierstil vergleichbar ist, denn es handelt sich in beiden Fällen um Anweisungen der Art „tue dies, tue das“. Diese „Befehle“ mit Variablen, Fallunterscheidungen, Sprüngen beschreiben das Programm und den Lösungsweg.
Zwar ist imperative Programmierung die technisch älteste, aber nicht die einzige Form Programme zu beschreiben; es gibt daneben die deklarative Programmierung, die nicht das „wie“ zur Problemlösung beschreibt, sondern das „was“, also was eigentlich gefordert ist ohne sich in genauen Abläufen zu verstricken. Auf den ersten Blick klingt das abstrakt, aber für jeden, der schon einmal
- einen Selektion wie *.html auf der Kommandozeile/im Explorer-Suchefeld getätigt,
- eine Datenbankanfrage mit SQL geschrieben,
- eine XML-Selektion mit XQuery genutzt,
- ein Build-Skript mit Ant oder make formuliert,
- eine XML-Transformation mit XSLT beschrieben hat
wird das Prinzip kennen.
Bleiben wir kurz bei SQL, um einen Punkt deutlich zu machen. Natürlich ist im Endeffekt die Abarbeitung der Tabellen und Auswertungen der Ergebnisse von der CPU rein imperativ, doch es geht um die Programmbeschreibung auf einem höheren Abstraktionsniveau. Deklarative Programme sind üblicherweise wesentlicher kürzer und damit kommen weitere Vorteile wie leichtere Erweiterbarkeit, Verständlichkeit ins Spiel. Da deklarative Programme oftmals einen mathematischen Hintergrund haben, lassen sich die Beschreibungen leichter formal in ihrer Korrektheit beweisen.
Deklarative Programmierung ist ein Programmierstil, und eine deklarative Beschreibung braucht eine Art „Ablaufumgebung“, denn SQL kann zum Beispiel keine CPU direkt ausführen. Aber statt nur spezielle Anwendungsfälle wie Datenbank- oder XML-Abfragen zu behandeln, können auch typische Algorithmen deklarativ formuliert werden, und zwar mit funktionaler Programmierung. Damit sind imperative Programme und funktionale Programme gleich mächtig in ihren Möglichkeiten.
Funktionale Programmierung und funktionale Programmiersprachen
Bei der funktionalen Programmierung stehen Funktionen im Mittelpunkt und ein im Idealfall zustandsloses Verhalten, in dem viel mit Rekursion gearbeitet wird. Ein typisches Beispiel ist die Berechung der Fakultät. Es ist n! = 1 · 2 · 3 · … · n, und mit Schleifen und Variablen, dem imperativen Weg, sieht sie so aus:
public static int factorial( int n ) { int result = 1; for ( int i = 1; i <= n; i++ ) result *= i; return result; }
Deutlich sind die vielen Zuweisungen und die Fallunterscheidung durch die Schleife abzulesen; die typischen Indikatoren für imperative Programme. Der Schleifenzähler erhöht sich, damit kommt Zustand in das Programm, denn der aktuelle Index muss ja irgendwo im Speicher gehalten werden. Bei der rekursiven Variante ist das ganz anders, hier gibt es keine Zuweisungen im Programm und die Schreibweise erinnert an die mathematische Definition:
public static int factorial( int n ) { return n == 0 ? 1 : n * factorial( n - 1 ); }
Mit der funktionalen Programmierung haben wir eine echte Alternative zur imperativen Programmierung. Die Frage ist nur: Mit welcher Programmiersprache lassen sich funktionale Programme schreiben? Im Grunde mit jeder höheren Programmiersprache! Denn funktional zu programmieren ist ja ein Programmierstil, und Java unterstützt funktionale Programmierung, wie wir am Beispiel mit der Fakultät ablesen können. Da das im Prinzip schon alles ist, stellt sich die Frage, warum funktionale Programmierung einen so schweren Stand hat und bei den Entwicklern gefürchtet ist. Das hat mehrere Gründe:
Lesbarkeit. Am Anfang der funktionalen Programmiersprachen steht historisch LISP aus dem Jahr 1958, eine sehr flexible, aber ungewohnt zu lesende Programmiersprache. Unsere Fakultät sieht in LISP so aus:
(defun factorial (n) (if (= n 1) 1 (* n (factorial (- n 1)))))
Die ganzen Klammern machen die Programme nicht einfach lesbar und die Ausdrücke stehen in der Präfix-Notation – n 1 statt der üblichen Infix-Notation n – 1. Bei anderen funktionalen Programmiersprachen ist es anders, dennoch führt das zu einem gewissen Vorurteil, dass alle funktionalen Programmiersprachen schlecht lesbar sind.
Performance und Speicherverbrauch. Ohne clevere Optimierungen von Seiten des Compilers und der Laufzeitumgebung führen insbesondere rekursive Aufrufe zu prall gefüllten Stacks und schlechter Laufzeit.
Rein funktional. Es gibt funktionale Programmiersprachen, die als „rein“ oder „pur“ bezeichnet werden und keine Zustandsänderungen erlauben. Die Entwicklung von Ein-/Ausgabeoperationen oder simplen Zufallszahlen ist ein großer Akt, der für normale Entwickler nicht mehr nachvollziehbar ist. Die Konzepte sind kompliziert, doch zum Glück sind die meisten funktionalen Sprachen nicht so rein und erlauben Zustandsänderungen, nur Programmierer versuchen genau diese Zustandänderungen zu vermeiden, um sich nicht die Nachteile damit einzuhandeln.
Funktional mit Java. Wenn es darum geht nur mit Funktionen zu arbeiten, kommen Entwickler schnell zu einem Punkt, an dem Funktionen andere Funktionen als Argumente übergeben oder Funktionen zurückgeben. So etwas lässt sich in Java in der traditionellen Syntax nur sehr umständlich schreiben. Dies führt dazu, dass alles so unlesbar wird, dass der ganze Vorteil der kompakten deklarativen Schreibweise verloren geht.
Aus heutiger Sicht stellt sich eine Kombination aus beiden Konzepten als zukunftsweisend dar. Mit der in Java 8 eingeführten Schreibweise der Lambda-Ausdrücke sind funktionale Programme kompakt und relativ gut lesbar und die JVM hat gute Optimierungsmöglichkeiten. Java ermöglicht beide Programmierparadigmen und Entwickler können den Weg wählen, der für eine Problemlösung gerade am Besten ist. Diese Mehrdeutigkeit schafft natürlich auch Probleme, denn immer wenn es mehrere Lösungswege gibt, entstehen Auseinandersetzungen um die Beste der Varianten – und hier kann von Entwickler zu Entwickler eine konträre Meinung herrschen. Funktionale Programmierung hat unbestrittene Vorteile und das wollen wir uns genau anschauen.
Funktionale Programmierung in Java am Beispiel vom Comparator
Funktionale Programmierung hat auch daher etwas akademisches, weil in den Köpfen der Entwickler oftmals dieses Programmierparadigma nur mit mathematischen Funktionen in Verbindung gebracht wird. Und die wenigsten werden tatsächlich Fakultät oder Fibonacci-Zahlen in Programmen benötigen und daher schnell funktionale Programmierung beiseite legen. Doch diese Vorurteile sind unbegründet, und es ist hilfreich, funktionale Programmierung gedanklich von der Mathematik zu lösen, denn die allermeisten Programme haben nichts mit mathematischen Funktionen im eigentlichen Sinne zu tun, wohl aber viel stärker mit formal beschriebenen Methoden.
Betrachten wir erneut unser Beispiel aus der Einleitung, die Sortierung von Strings, diesmal aus der Sicht eines funktionalen Programmierers. Ein Comparator ist eine einfache „Funktion“, mit zwei Parametern und einer Rückgabe. Diese „Funktion“ (realisiert als Methode) wiederum wird an die sort(…)-Methode übergeben. Alles das ist funktionale Programmierung, denn wir programmieren Funktionen und übergeben sie. Drei Beispiele (Generics ausgelassen):
Code | Bedeutung |
Comparator c = (c1, c2) -> … | Implementiert eine Funktion über Lambda-Ausdruck |
Arrays.sort(T[] a, Comparator c) | Nimmt eine Funktion als Argument an |
Collections.reverseOrder(Comparator cmp) | Nimmt eine Funktion an und liefert auch eine zurück |
Beispiele für Funktionen in der Übergabe und als Rückgabe
Funktionen selbst können in Java nicht übergeben werden, also helfen sich Java-Entwickler mit der Möglichkeit, die Funktionalität in eine Methode zu setzen, sodass die Funktion zum Objekt mit einer Methode wird, was die Logik realisiert. Lambda-Ausdrücke bzw. Methoden/Konstruktor-Referenzen geben eine kompakte Syntax ohne den Ballast, extra eine Klasse mit einer Methoden schreiben zu müssen.
Der Typ Comparator ist eine funktionale Schnittstelle und steht für eine besondere Funktion mit zwei Parametern gleichen Typs und einer Ganzzahl-Rückgabe. Es gibt weitere funktionale Schnittstellen, die etwas flexibler sind als Comparator, in der Weise, dass etwa die Rückgabe statt int auch double oder etwas anderes sein können.
Lambda-Ausdrücke als Funktionen sehen
Wir haben gesehen, dass sich Lambda-Ausdrücke in einer Syntax formulieren lassen, die folgende allgemeine Form hat:
‚(‚ LambdaParameter ‚)‘ ‚->‘ ‚{‚ Anweisungen ‚}‘
Der Pfeil macht gut deutlich, dass wir es bei Lambda-Ausdrücken mit Funktionen zu tun haben, die etwas abbilden. Im Fall vom Comparator ist es eine Abbildung von zwei Strings auf eine Ganzzahl; in einer etwas mathematischeren Notation gepackt: (String, String) → int.
Beispiel Methoden gibt es mit und ohne Rückgabe und mit und ohne Parameter. Genauso ist das mit Lambda-Ausdrücken. Ein paar Beispiele in Java-Code mit ihren Abbildungen.
Lambda-Ausdruck | Abbildung |
(int a, int b) -> a + b | (int, int) → int |
(int a) -> Math.abs( a ) | (int) → int |
(String s) -> s.isEmpty() | (String) → boolean |
(Collection c) -> c.size() | (Collection) → int |
() -> Math.random() | () → double |
(String s) -> { System.out.print( s ); } | (String) → void |
() -> {} | () → void |
Lambda-Ausdrücke und was sie als Funktionen abbilden
Begriff: Funktion vs. Methode. Die Java Sprachdefinition kennt den Begriff „Funktion“ nicht, sondern spricht nur von Methoden. Methoden hängen immer an Klassen und das heißt, dass Methoden immer an einem Kontext hängen. Das ist zentral bei der Objektorientierung, da Methoden auf Attribute lesend und schreibend zugreifen können. Lambda-Ausdrücke wiederum realisieren Funktion, die erst einmal ihre Arbeitswerte rein aus den Parametern beziehen, sie hängen nicht an Klassen und Objekten. Der Gedanke bei funktionalen Programmiersprachen ist der, ohne Zustände auszukommen, also Funktionen so clever anzuwenden, dass sie ein Ergebnis liefern. Funktionen geben für eine spezifische Parameterkombination immer dasselbe Ergebnis zurück, unabhängig vom Zustand des umgebenden Gesamtprogramms.
Kleine Oracle Webinars zu Java 8
LaF von Eclipse anpassen mit dem Full Featured Eclipse Theme Customizer
Wer Eclipse ein neues Kleid geben möchte, sollte sich das Projekt unter https://github.com/jeeeyul/eclipse-themes einmal anschauen: