UncheckedIOException in Java 8

Fehler bei Ein-/Ausgabe-Operationen werden in Java traditionell über eine geprüfte Ausnahme vom Typ IOException gemeldet. Bei Frameworks ist das zum Teil etwas lästig, sodass Java 8 eine Wrapper-Klasse im Paket java.io aufgenommen hat, die eine geprüfte IOException in einer ungeprüften UncheckedIOException mantelt.

class java.io.UncheckedIOException
extends RuntimeException

§ UncheckedIOException(IOException cause)
Ummantelt cause.

§ UncheckedIOException(String message, IOException cause)
Ummantelt cause mit einer zusätzlichen Meldung.

Bisher macht die Java-Bibliothek nur an einer Stelle von diesem Ausnahmetyp Gebrauch, und das ist bei lines() der Klasse BufferedReader, damit bei der Stream-API die geprüften Ausnahmen nicht im Wege stehen.

BufferedReader#lines, Files.newBufferedReader()

Der BufferedReader bietet neben den einfachen geerbten Lese-Methoden der Oberklasse Reader zwei weitere praktische Methoden:

· String readLine(): liest eine Zeile, und liefert am Ende null, wenn die letzte Zeile erreicht wurde.

· Stream<String> lines(): Liefert einen Stream von Strings. Neu in Java 8.

So ist einfach ein Programm formuliert, welches alle Zeilen einer Datei abläuft:

try ( BufferedReader in = Files.newBufferedReader( Paths.get( "lyrics.txt" ), StandardCharsets.ISO_8859_1 ) ) {

for ( String line; (line = in.readLine()) != null; )

  System.out.println( line );

}

catch ( IOException e ) {

  e.printStackTrace();

}

Beispiel

Mit der Stream-API sieht es ähnlich aus; kurz skizziert:

try ( BufferedReader in = Files.newBufferedReader( … ) ) {

  in.lines().forEach( System.out::println );

}

Falls es beim Lesen über den Stream zu einem Fehler kommt, wird eine RuntimeException vom Typen UncheckedIOException ausgelöst.

CharSequence-Erweiterungen seit Java 8

In Java 8 vergrößert sich die Schnittstelle um zwei Default-Methoden:

interface java.lang.CharSequence

§ default IntStream chars()

§ default IntStream codePoints()

Alle implementierenden Klassen bieten ab Java 8 diese beiden zusätzlichen Methoden. Die Bedeutung von default und Schnittstellen im Allgemeinen bleibt ein Detail aus Kapitel 6, an dieser Stelle wollen wir nur den Vorteil betonen, dass chars() gut dafür verwendet werden kann, über die Zeilen zu laufen. Allerdings hat das nichts mit dem erweiterten for zu tun, sondern mit einem anderen Programmieridiom.

Beispiel

Laufe über eine Zeichenkette und gib jedes Zeichen aus.

"Drama is life with the dull bits left out. (Hitchcock)".chars().forEach( c ->

System.out.print( (char) c )

);

Arrays.setAll(…)/parallelSetAll(…)

Neben der Möglichkeit ein Feld mit festen Werten zu füllen, sind in Java 8 noch ein paar Methoden setAll(…)/parallelSetAll(…) hinzugekommen. Die Methoden durchlaufen ein gegebenes Feld und rufen eine bestimmte Methode für jeden Index auf, die zur Initialisierung verwendet wird.

Beispiel

Fülle ein double-Feld mit Zufallszahlen:

double[] randoms = new double[10];

Arrays.setAll( randoms, v -> Math.random() );

System.out.println( Arrays.toString( randoms ));

Das Beispiel nutzt eine spezielle Syntax, die sogenannten Lambda-Ausdrücke, um die Funktion zu beschreiben.

class java.util.Arrays

  • static void setAll(double[] array, IntToDoubleFunction generator)
  • static void setAll(int[] array, IntUnaryOperator generator)
  • static void setAll(long[] array, IntToLongFunction generator)
  • static <T> void setAll(T[] array, IntFunction<? extends T> generator)
  • static void parallelSetAll(double[] array, IntToDoubleFunction generator)
  • static void parallelSetAll(int[] array, IntUnaryOperator generator)
  • static void parallelSetAll(long[] array, IntToLongFunction generator)
  • static <T> void parallelSetAll(T[] array, IntFunction<? extends T> generator)
    Läuft ein gegebenes Feld komplett ab und übergibt dabei dem generator Schritt für Schritt den Index. Der Generator bildet den Index auf einen Wert ab, der wiederum zur Feldinitialisierung genutzt wird.

Arrays.parallelSort(…)

In Java 8 sind neue Sortiermethoden hinzugekommen, die für sehr große Felder geeignet sind. Bei den neuen parallelSort(…)-Methoden verwendet die Bibliothek mehrere Threads um Teile parallel zu sortieren, was die Geschwindigkeit erhöhen kann. Eine Garantie ist das aber nicht, denn ein Performance-Vorteil ergibt sich wirklich nur bei großen Feldern.

class java.util.Arrays

§ static void parallelSort(byte[] a)

§ static void parallelSort(byte[] a, int fromIndex, int toIndex)

§ static void parallelSort(char[] a)

§ static void parallelSort(char[] a, int fromIndex, int toIndex)

§ static void parallelSort(short[] a)

§ static void parallelSort(short[] a, int fromIndex, int toIndex)

§ static void parallelSort(int[] a)

§ static void parallelSort(int[] a, int fromIndex, int toIndex)

§ static void parallelSort(long[] a)

§ static void parallelSort(long[] a, int fromIndex, int toIndex)

§ static void parallelSort(float[] a)

§ static void parallelSort(float[] a, int fromIndex, int toIndex)

§ static void parallelSort(double[] a)

§ static void parallelSort(double[] a, int fromIndex, int toIndex)

§ static <T extends Comparable<? super T>> void parallelSort(T[] a)

§ static <T extends Comparable<? super T>> void parallelSort(T[] a, int fromIndex, int toIndex)

§ static <T> void parallelSort(T[] a, Comparator<? super T> c)

§ static <T> void parallelSort(T[] a, int fromIndex, int toIndex, Comparator<? super T> c)

Der verwendete Algorithmus ist einfach zu verstehen: zunächst wird das Feld ist Teilfelder partitioniert, die werden dann parallel sortiert und dann zu einem größeren sortierten Feld zusammengelegt. Das Verfahren nennt sich auch parallel sort-merge.

Na endlich sieht Java 8’s Optional-Typ besser aus

http://download.java.net/jdk8/docs/api/java/util/Optional.html:

static <T> Optional<T>
empty()

Returns an empty Optional instance.

boolean
equals(Object obj)

Indicates whether some other object is "equal to" this Optional.

T
get()

If a value is present in this Optional, returns the value, otherwise throws NoSuchElementException.

int
hashCode()

Returns the hash code value of the present value, if any, or 0 (zero) if no value is present.

void
ifPresent(Consumer<? super T> consumer)

Have the specified consumer accept the value if a value is present, otherwise do nothing.

boolean
isPresent()

Return true if there is a value present, otherwise false.

static <T> Optional<T>
of(T value)

Return an Optional with the specified present value.

T
orElse(T other)

Return the value if present, otherwise return other.

T
orElseGet(Supplier<? extends T> other)

Return the value if present, otherwise invoke other and return the result of that invocation.

<X extends Throwable>
T

orElseThrow(Supplier<? extends X> exceptionSupplier)

Return the contained value, if present, otherwise throw an exception to be created by the provided supplier.

String
toString()

Returns a non-empty string representation of this Optional suitable for debugging.

 

Was mir immer noch fehlt: fromNullable(v). Arg, das fehlt.

Java und Unendlich

Der Überlauf einer mathematischen Operation führt zu einem positiven oder negativen Unendlich.

Beispiel

Multiplikation zweier wirklich großer Werte:

System.out.println( 1E300 * 1E20 ); // Infinity
System.out.println( –1E300 * 1E20 ); // -Infinity

Für die Werte deklariert die Java-Bibliothek in Double und Float zwei Konstanten; zusammen mit der größten und kleinsten darstellbaren Fließkommazahl sind das:

Wert für

Float

Double

positiv unendlich

Float.POSITIVE_INFINITY

Double.POSITIVE_INFINITY

negativ unendlich

Float.NEGATIVE_INFINITY

Double.NEGATIVE_INFINITY

kleinster Wert

Float.MIN_VALUE

Double.MIN_VALUE

größter Wert

Float.MAX_VALUE

Double.MAX_VALUE

Tabelle 1.8: Spezialwerte und ihre Konstanten

Das Minimum für double-Werte liegt bei etwa 10^–324 und das Maximum bei etwa 10^308. Weiterhin deklarieren Double und Float Konstanten für MAX_EXPONENT/MIN_EXPONENT.

Hinweis

Die Anzeige des Über-/Unterlaufs und des undefinierten Ergebnisses gibt es nur bei Fließkommazahlen, nicht aber bei Ganzzahlen.

public final class java.lang.Float/Double
extends Number
implements Comparable<Float/Double>

§ static boolean isInfinite(float/double v)
Liefert true, wenn v entweder POSITIVE_INFINITY oder NEGATIVE_INFINITY ist.

§ static boolean isFinite(float/double d)
Liefert true, wenn d eine endliche Zahl ist. Neu in Java 8.

Blöcke mit Code und die funktionale Schnittstelle java.util.function.Consumer

Anweisungen von Code lassen sich in eine Methode eines Objekts setzen und auf diese Weise weitergeben. Das ist eine häufige Notwendigkeit, für die das Paket java.util.function eine einfache funktionale Schnittstelle Consumer vorgibt:

interface java.util.function.Consumer<T>

*  void accept(T t). Führt Operationen mit der Übergabe t durch.

Die accept(…)-Methode bekommt ein Argument – wobei die Implementierung natürlich nicht zwingend darauf zurückgreifen muss – und liefert keine Rückgabe. Transformationen sind damit nicht möglich, denn nur über Umwege kann der Konsument die Ergebnisse speichern, und dafür ist die Schnittstelle nicht gedacht. Consumer-Typen sind eher gedacht als Endglied einer Kette, in der zum Beispiel Dateien in eine Datei geschrieben werden, die vorher verarbeitet wurden.

Immer repräsentieren Konsumenten Code, und eine API kann nun einfach einen Code-Block nach der Art doSomethingWith(myConsumer) annehmen, und ihn etwa in einem Hintergrund-Thread abzuarbeiten, wiederholend auszuführen, nach einer erlaubten Maximaldauer abbrechen, die Zeit messen, …

Beispiel

Implementiere einen Consumer-Wrapper, der die Ausführungszeit eines anderen Konsumenten loggt.

import java.util.function.*;

import java.util.logging.Logger;

class Consumers {

public static <T> Consumer<T> measuringConsumer( Consumer<T> block ) {

return t -> {

long start = System.nanoTime();

block.accept( t );

long duration = System.nanoTime() – start;

Logger.getAnonymousLogger().info( "Ausführungszeit (ms): " + duration );

};

}

}

Folgender Aufruf zeigt die Nutzung:

Consumer<Void> wrap = measuringConsumer( (Void) -> System.out.println( "Test" ) );

wrap.accept( null );

Typ Consumer in der API

In der Java-API zeigt sich der Typ Consumer in der Regel als Argument einer Methode forEach(Consumer), die Datenquellen abläuft und für jedes Element accept(…) aufruft. Interessant ist die Methode an dem Typ Iterable, denn die wichtigen Collection-Datenstrukturen wie ArrayList implementieren diese Schnittstelle.

Beispiel

Gib jedes Element einer Liste auf der Konsole aus:

Arrays.asList(1, 2, 3, 4).forEach( t -> System.out.println( t ) );

Prädikate und java.util.function.Predicate

Ein Prädikat ist eine Aussage über einen Gegenstand, die wahr oder falsch. Die Frage mit Character.isDigit(‚a‘), ob das Zeichen „a“ eine Ziffer ist, wird mit falsch beantwortet – isDigit ist also ein Prädikat, weil es über einen Gegenstand, einem Zeichen, eine Wahrheitsaussage fällen kann.

Flexibler sind Prädikate, wenn sie als Objekte repräsentiert werden, weil sie dann an unterschiedliche Stellen weitergegeben werden können, wenn etwa über ein Prädikat bestimmt, was aus einer Sammlung gelöscht werden soll oder ob mindestens ein Element in einer Sammlung ist, was ein Prädikat erfüllt.

Das java.util.function-Paket deklariert eine flexible funktionale Schnittstelle Predicate auf folgende Weise:

interface java.util.function.Predicate<T>

* boolean test(T t)
   Führt einen Test auf t durch und liefert true, wenn das Kriterium erfüllt ist.

Beispiel

Der Test, ob ein Zeichen eine Ziffer ist, kann durch Prädikat-Objekte nun auch anders durchgeführt werden:

Predicate<Character> isDigit = (Character c) -> Character.isDigit( c );

System.out.println( isDigit.test(‚a‘) ); // false

Hätte es die Schnittstelle Predicate schon früher in Java 1.0 gegeben, hätte es einer der Methode Character.isDigit(…) gar nicht bedurft, es hätte auch ein Predicate als statische Variable in Character geben können, so dass ein Test dann geschrieben würde als Character.IS_DIGIT.test(…) oder als Rückgabe von einer Methode isDigit(), mit der Nutzung Character.isDigit().test(…). Es ist daher gut möglich, dass sich in Zukunft die API dahingehend verändert, dass Aussagen auf Gegenständen mit Wahrheitsrückgabe nicht mehr als Methoden bei den Klassen realisiert werden, sondern als Prädikat-Objekte angeboten werden. Aber Methoden-Referenzen geben zum Glück die Flexibilität, dass problemlos Methoden als Lambda-Ausdrücke genützt werden können und so kommen wir wieder von Methoden zu Funktionen.

Typ Predicate in der API

Es gibt in der Java-API vier Stellen, an denen Prediate-Objekte genutzt werden:

· Als Argument für Lösch-Methoden, um in Sammlungen Elemente zu spezifizieren, die gelöscht werden sollen.

· Bei den Default-Methoden der Predicate-Schnittstelle selbst, um Prädikate zu verknüpfen.

· Bei regulären Ausdrücken, um ein Pattern als Predicate nutzen zu können.

· In der Stream-API, bei der Objekte beim Durchlaufen des Stroms über ein Prädikat identifiziert werden, um sie etwa auszufiltern.

Beispiel

Lösche aus einer Liste mit Zeichen alle die, die Ziffern sind (es bleiben nur Zeichen übrig, etwa Buchstaben).

Predicate<Character> isDigit = (Character c) -> Character.isDigit( c );

List<Character> list = new ArrayList( Arrays.asList( ‚a‘, ‚1‘ ) );

list.removeIf( isDigit );

Default-Methoden von Predicate

Es gibt eine Reihe von Default-Methoden, die die funktionale Schnittstelle Predicate anbietet. Zusammenfassend:

interface java.util.function.Predicate<T>

default Predicate<T> negate()

default Predicate<T> and(Predicate<? super T> p)

default Predicate<T> or(Predicate<? super T> p)

default Predicate<T> xor(Predicate<? super T> p)

Die Methodennamen sprechen für sich.

Beispiel

Lösche aus einer Liste mit Zeichen alle die, die keine Ziffern sind.

Predicate<Character> isDigit = (Character c) -> Character.isDigit( c );

Predicate<Character> isNotDigit = isDigit.negate();

List<Character> list = new ArrayList( Arrays.asList( ‚a‘, ‚1‘ ) );

list.removeIf( isNotDigit );

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, gedanklich funktionale Programmierung von der Mathematik lösen, denn die allermeisten Programme haben nichts mit mathematischen Funktionen im eigentlichen Sinne zu tun.

Betrachten wir die Sortierung von Strings. Ein Comparator ist eine einfache Funktion, mit zwei Parametern und einer Rückgabe. Diese Funktion 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

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

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 kapseln, sodass die Funktion zum Objekt mit einer Methode wird, was die Logik realisiert. Lambda-Ausdrücke bzw. Methoden/Konstruktor-Referenzen geben eine kompakte Syntax.

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.

Imperative und funktionale Programmierung

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 Programmierparadigma 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 im *.html auf der Kommandozeile genutzt,

· eine Datenbankanfrage mit SQL geschrieben,

· eine XML-Selektion mit XQuery getätigt,

· 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 oftmals deklarative Programme 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 es 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. 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 schwer 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 greifen so selten wie nötig darauf zurück.

Funktional mit Java. Wenn es darum geht nur mit Funktionen zu arbeiten, kommen Entwickler schnell zu einem Punkt, dass 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, 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 da. 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 unbestritten Vorteile und das wollen wir uns genau anschauen.

Thema der Woche: Google Cache

  • Studiere aufmerksam https://code.google.com/p/guava-libraries/wiki/CachesExplained.
  • Schreibe ein Swing-Programm mit einer JList und einem eigenen Listen-Model, was zu einem Index die Primfaktorzerlegung berechnet (benutze Google und suche eine Implementierung). Bei 1 wird also 1 angezeigt, bei 2 folgt 1*2, bei 3 dann 3, bei 4 folglich 2*2 usw.
  • Das Ergebnis soll nicht mehr live berechnet werden, sondern über den Google Cache zwischengespeichert werden, was ein beschleunigtes Scrollen bewerkstelligen sollte. Wie lässt sich das integrieren?
  • Gibt es mehrere Möglichkeiten den Google Cache in dem Szenario einzusetzen?

Thema der Woche: Paketierung mit <fx:deploy>

Seit Neustem kann man mit Java auch ausführbare Dateien bzw. Installer bauen. Ließ dazu http://docs.oracle.com/javafx/2/deployment/self-contained-packaging.htm bzw. suche nach weiterer Dokumentation im Netz.

  • Teste das an einer eigenen kleinen Hello-World-Anwendung.
  • Wie groß ist das Ergebnis mit JRE?
  • Welche Zielformate sind möglich und kann man alle etwa auf einem Linux-Build-Server bauen?
  • Nutze log4j und nimm die Jar mit in das Zielformat mit auf. Lassen sich auch native Dateien einbinden?
  • Gilt diese Möglichkeit nur für JavaFX oder auch für für AWT/Swing oder SWT?

Java 8 könnte auf 18. März 2014 verschoben werden, wäre dann aber “Der Profi”

Bisher Vorschläge!

  • http://mail.openjdk.java.net/pipermail/jdk8-dev/2013-April/002336.html
  • http://mreinhold.org/blog/secure-the-train
  •   2013/05/09  M7  Feature Complete
      2013/07/18      Rampdown start
      2013/09/05  M8  Developer Preview
      2013/09/12      All Tests Run
      2013/10/10      API/Interface Freeze
      2013/10/24      Zero Bug Bounce
      2013/11/21      Rampdown phase 2
      2014/01/23  M9  Final Release Candidate
      2014/03/18  GA  General Availability

    Der 18.03. ist bestimmt kein Zufall, denn Luc Besson hat Geburtstag, und der ist uns ja in Erinnerung mit dem 1994er Klassiker “Der Profi”mit Jean Reno (nicht der mit Jean-Paul Belmondo, der war 1981). Damit wird Java 8 bestimmt auch so ein Profi im Bereich Sicherheit (naja, der Profi stirbt am Ende), sodass wir alle sagen können “Hier wird es uns gut gehen, Java”.

    Java 9 kommt dann in der ersten Hälfte von 2016. Oder irgendwann.

    Buchkritik: Wicked Cool Java: Code Bits, Open-Source Libraries, and Project Ideas

    Brian Eubanks; ISBN-10: 1593270615; No Starch Press; 15.11.2005; 248 Seiten
    Mit dem Buch hat Brian eigentlich das gemacht, was sich jeder Autor wünscht: sich hinzusetzen und einfach mal im Artikelstil über alles zu schreiben, was einem interessiert, ohne darauf zu achten, ob das nützlich oder wichtig ist. Dafür nimmt er sich 8 Kapitel Zeit:
    Chapter 1: Java Language and Core API, Chapter 2: String Utilities, Chapter 3: Processing XML and HTML, Chapter 4: Crawling the Semantic Web, Chapter 5: Math and Science, Chapter 6: Graphics and Data Visualization, Chapter 7: Multimedia and Sychronization, Chapter 8: Fun, Integration and Project Ideas. Im Grunde ist nur das erste Kapitel ein kleines Einstiegskapitel, insbesondere in die Neuerungen von Java 5, und zusammen mit dem zweiten Kapitel haben sie die Java SE selbst zum Inhalt. Das Niveau ist an Anfang niedrig und passt nicht zum Rest. Syntaktisch ist nicht immer alles sauber, so gibt es immer wieder umständliche Feldinitialisierungen wie int[] theList = new int[]{2,3,5,7}; oder java.util.Random random = new Random(); wo ich mich Frage, ob der Autor dort gerade wach war. Dann wird assert geklammert wie eine Methodenaufruf, das ist aber nur in C so, nicht in Java, wo assert ein Schlüsselwort ist und der Ausdruck nicht geklammert wird. (Macht Krüger im Buch aber leider auch so.) Leider sind auch nicht alle Beispiele konsequent auf Java 5 ausgelegt, immer wieder findet sich der Raw-Type etwa von Datenstrukturen, bei seinen verketten Listen-Implementierung oder mit verketteten Knoten wiederum fehlt ein Generic, hier steht nur Object content. An anderer Stelle im Buch gibt es den Hinweis, das ein Listing mit Generics auf der Buchseite (http://www.wickedcooljava.com/) ist, warum nicht gleich im Code? Mit Generics scheint Brian auch noch nicht so vertraut zu sein, anders kann ich mir nicht erklären, warum er eine Methode removeMatches(List<Number> aList) schreibt, denn man muss verstehen, da man so etwas nicht zum Beispiel mit einer List<Double> aufrufen kann; eleganter wäre ein Typ-Bound er Art List<? extends Number> hin. Weiter: Statt StringBuilder kommt noch StringBuffer zum Einsatz. Nicht gut gefällt mir auch der Bezug auf konkrete Klasse, statt Basistypen, etwa bei ArrayList<String> getNames(), hier würde als Rückgabe auch List oder Collection reichen. (In dem gleichen Beispiel ist auch unglücklich den Scanner auch nicht im finally zu schließen. Und getFloat() statt getDouble() zu nehmen ist auch Geschmackssache.) Bei den Farben verwendet der Autor noch die klein geschriebenen Namen also Color.blue statt Color.BLUE. Sehr geschwätzig ist auch if ( … ) { return true; } else { return false; } — das ist uncool.
    Im Mittelpunkt des Buches geht es um wilde Open-Source Bibliotheken, etwa für mathematische Operationen, Textanalyse, Suche (nicht wild), semantische Netze, RDF, MIDI-Sounds. Eigentlich nichts, was man wirklich/dringend/oft bräuchte, und wenn, würde man vermutlich in ein spezielles Buch schauen. Positiv ist anzumerken, dass uns der Autor die Libs vorstellt und des Lesers Horizont erweitert. Ein Probekapitel gibt es nicht online, allerdings unter http://www.wickedcooljava.com/related.jsp eine Linkliste der Bibliotheken. April 2013

    Assertions feiner aktivieren oder deaktivieren

    Assertions müssen nicht global für das ganze Programm gesetzt werden, sondern könne auch feiner deklariert werden, etwa für eine Klasse oder ein Paket. Mit geschickter Variation von –ea (Assertions aktivieren) und –da (Assertions desaktivieren) lässt seht gut steuern, was die Laufzeitumgebung prüfen soll.

    Beispiel

    Aktiviere Assertions für die Klasse com.tutego.App:

    $ java -ea:com.tutego.App AppWithMain

    Aktiviere Assertions für das Default-Paket (dafür stehen die drei Punkte):

    $ java -ea:… AppWithMain

    Aktiviere Assertions für das Paket com.tutego inklusive aller Unterpakete (auch dafür stehen drei Punkte):

    $ java -ea:com.tutego… AppWithMain

    Aktiviere Assertions für das Paket com.tutego inklusive aller Unterpakete, aber desaktiviere sie für die Klasse App in dem Paket com.tutego:

    $ java -ea:com.tutego… -da:com.tutego.App AppWithMain

    Assertions müssen Nebeneffekt frei sein

    Assertions stehen immer in der Klassendatei, da sie der Compiler immer in Bytecode abbildet. Die JVM ignoriert Assertions standardmäßig bei der Ausführung und eine Aktivierung erfolgt nur auf Befehl; ein Ablauf ohne Bedingungstests ist also der Normalfall. Daraus folgt, dass Ausdrücke in den assert-Anweisungen ohne Nebeneffekte sein müssen. So etwas wie

    assert counter– == 0;

    ist keine gute Idee, denn das Vermindern der Variablen ist ein Nebeneffekt, der nur dann stattfindet, wenn die JVM auch Assertions aktiviert hat. Allerdings lässt sich das auch für einen Trick nutzen, Assertions bei der Ausführung zu erzwingen. Im statischen Initialisierer einer Klasse können wir setzen:

    boolean assertEnabled = false;

    assert assertEnabled = true;

    if ( ! assertEnabled )

      throw new RuntimeException( "Assertions müssen aktiviert werden" );