Alle Neuerungen von Java 8 über die Javadoc finden

Im folgenden Beispiel wollen wir ein kleines Doclet schreiben, das Klassen, Methoden und Konstruktoren ausgibt, die das Tag @since 1.8 (bzw. @since 8, was aber eigentlich falsch ist) tragen. So lässt sich leicht ermitteln, was in der Version Java 8 alles hinzugekommen ist. Doclets werden normalerweise von der Kommandozeile aufgerufen und dem javadoc-Tool übergeben. Unser Programm vereinfacht das, indem es direkt das Tool über Java mit dem passenden Parameter aufruft. tools.jar muss dafür im Klassenpfad sein und die Dokumentation ausgepackt am angegeben Ort.

package com.tutego.tools.javadoc;

import java.util.*;
import java.util.function.Predicate;
import com.sun.javadoc.*;
import com.sun.tools.javadoc.Main;

public class SinceJava8FinderDoclet {

  public static boolean start( RootDoc root ) {
    for ( ClassDoc clazz : root.classes() )
      processClass( clazz );
    return true;
  }

  private static void processClass( ClassDoc clazz ) {
    Predicate<Tag> isJava18 = tag -> tag.text().equals( "8" ) || tag.text().equals( "1.8" );

    if ( Arrays.stream( clazz.tags( "since" ) ).anyMatch( isJava18 ) )
      System.out.printf( "Neuer Typ %s%n", clazz );

    for ( MethodDoc method : clazz.methods() )
      if ( Arrays.stream( method.tags( "since" ) ).anyMatch( isJava18 ) )
        System.out.printf( "Neue Methode %s%n", method );

    for ( ConstructorDoc constructor : clazz.constructors() )
      if ( Arrays.stream( constructor.tags( "since" ) ).anyMatch( isJava18 ) )
        System.out.printf( "Neuer Konstruktor %s%n", constructor );

    for ( FieldDoc field : clazz.fields() )
      if ( Arrays.stream( field.tags( "since" ) ).anyMatch( isJava18 ) )
        System.out.printf( "Neues Attribut %s%n", field );
  }

  public static void main( String[] args ) {
    String[] params = {
        "-quiet", "-XDignore.symbol.file",
        "-doclet", SinceJava8FinderDoclet.class.getName(),
        "-sourcepath", "C:/Program Files/Java/jdk1.8.0/src/",
//        "java.lang",  // Nur java.lang
        "-subpackages", "java:javax"  // Alles rekursiv unter java.* und javax.*
    };
    Main.execute( params );
  }
}

Unsere main(String[])-Methode ruft das JDK-Doclet-Programm über Main.execute(String[]) auf und übergibt die eigene Doclet-Klasse per Parameter – die Argumente von execute(String[]) erinnern an die Kommandozeilenparameter. Das Doclet-Hauptprogramm wiederum ruft unsere start(RootDoc root)-Methode auf – das Gleiche würde auch passieren, wenn das Doclet von außen über javadoc aufgerufen würde. Unser start(RootDoc) läuft über alle ermittelten Typen und übergibt zum Abarbeiten der Innereien die Verantwortung an processClass(ClassDoc). Die Metadaten kommen dabei über diverse XXXDoc-Typen. Ein Precidate zieht den Tag-Test heraus, ein weiterer Einsatz der neuen Java 8 Streams würde das Programm nicht übersichtlicher machen.

Das Programm nutzt ein paar Tricks, um die Ausgabe auf das Wesentliche zu konzentrieren. Der Schalter –quit schaltet den üblichen Ladestatus, der zu Ausgaben wie

Loading source files for package java.lang…

Loading source files for package java.applet…

Loading source files for package java.awt…

führt ab.

Der Schalter -XDignore.symbol.file wiederum unterdrückt Meldungen wie diese hier:

C:\…\src\java\lang\Class.java:57: warning: Unsafe is internal proprietary API and may be removed in a future release

import sun.misc.Unsafe;

^

Die Meldungen landen auf dem System.err-Kanal, sodass sie sich auch mit System.setErr(…) in einem ausgabeverwerfenden Strom geschickt werden können um sie zu unterdrücken.

Geschichte von JavaFX: JavaFX 1, JavaFX 2, JavaFX 8

Ursprünglich wollte Sun/Oracle JavaFX als Flash-Ersatz im Internet positionieren, doch dafür ist die Kombination HTML5 + CSS3 + JavaScript zu attraktiv. JavaFX ist in erster Linie eine großartige GUI-Bibliothek für klassische Client-Anwendungen, die langsam auch auf mobile Endgeräte vorrückt. So nahm die Entwicklung auch unterschiedliche Richtungen an.

JavaFX ist schon sehr lange in Entwicklung und viele interne Swing-Entwickler wurden bei Sun/Oracle auf das Projekt angesetzt – umgekehrt passierte bei AWT/Swing nicht mehr viel, Bugfixes kommen aber immer noch brav. Im Jahr 2007 wurde JavaFX auf der SunOne-Konferenz vorgestellt, Ende 2008 erschien das Release JavaFX 1.0 zusammen mit der Programmiersprache JavaFX Script. Die besondere Sprache machte es einfach möglich, hierarchische Objektgrafen aufzubauen, und bot eine nette Syntax für Object-Binding, sodass Zustände synchronisiert werden konnten.

Im Oktober 2011 erschien JavaFX 2.0 mit vielen Neuerungen und auch Änderungen. So wurde JavaFX Script entfernt, denn Oracle wollte keine weitere Programmiersprache aufbauen, sondern eine pure Java API, die Entwickler dann von unterschiedlichen existierenden Skriptsprachen ansprechen können. Das ist sicherlich eine gute Entscheidung, denn unter JavaScript und Groovy[1] sieht das sehr schlank aus, fast wie mit JavaFX Script. Mit dem Update auf JavaFX 2.0 ändert sich auch die API, sodass alter Code angefasst werden musste. Heute ist JavaFX 1.x ist veraltet, genauso wie die Literatur.

JavaFX entwickelte sich immer mehr als Alternative zu Swing/AWT und so integrierte Oracle im August 2012 das Java FX 2.2 SDK und die Runtime in das JDK 7u6 and JRE 7u6. Der Schritt war ungewöhnlich, denn so große Ergänzungen waren bisher im JRE/JDK noch nie gemacht worden. Neben der Integration bewegte sich auch das ehemals geschlossene JavaFX in Richtung Open-Source und mündete in der Implementierung OpenJFX. Mit dem OpenJDK und OpenJFX lässt sich ein komplett freies Java-System mit GUI-Stack unter der GPL bauen, was strikte Linux-Distributionen freuen wird. Die Offenheit führte schon zu sehr spannenden Experimenten, etwa einer Java-Version für iOS.

Mit Java 8 zieht auch JavaFX 8 fest in die Distribution ein, der nächste Sprung mit 3D-Unterstützung.


[1] http://groovyfx.org/

Wiederholbare Annotationen: @Repeatable

Normalerweise nutzen Entwickler Annotationen wie einmalige Modifizierer, und es ergibt keinen Sinn, etwa @Override @Override String toString() zu schreiben, genauso wenig wie es keinen Sinn ergibt final static final double PI zu deklarieren. Doch da es durchaus Meta-Daten gibt, die mehrmals auftauchen können, gibt es seit Java 8 eine Erweiterung, dass Annotationen wiederholt werden dürfen. Allerdings müssen die Annotationstypen dieser wiederholbaren Annotationen selbst mit einer besonderen Meta-Annotation @Repeatable ausgezeichnet werden. Damit ist es aber noch nicht getan, denn @Repeatable muss als Element einen Typ bekommen, der den Container angibt.

Beispiel: Der Annotationstyp für Autoren kann so aussehen:

public @interface Author { String name(); }

Soll nun die Annotation mehrfach verwendet werden, ist die Meta-Annotation nötig und mit ihr die Angabe eines Containers:

@Repeatable( Authors.class )
public @interface Author { String name(); }

Der Container ist selbst ein Annotationstyp mit einem Feld als Element. Der Typ des Feldes ist exakt der wiederholbare Annotationstyp.

public @interface Authors {
  Autor[] value;
}

Ohne @Repeatable am Annotationstyp wird eine mehrmalige Verwendung einer Annotation zu einem Compilerfehler führen. Im Java SE 8 gibt es bisher keine Verwendung dieses Annotationstyps, also auch keine wiederholbaren Annotationen.

@Target Annotation seit Java 8

Die Meta-Annotation @java.lang.annotation.Target beschreibt, wo eine Annotation angeheftet werden kann. Ist kein ausdrückliches @Target gewählt, gilt es für alle Elemente, die Annotation kann also etwa an Klassen stehen, aber auch an lokalen Variablen. In der Regel gibt es bei @Target ein Element, und das ist von der Aufzählung java.lang.annotation.ElementType; es deklariert die folgenden Ziele:

ElementType

Erlaubt Annotationen …

ANNOTATION_TYPE

nur an anderen Annotationstypen, was @Target(ANNOTATION_TYPE) somit zu einer Meta-Annotation macht.

TYPE

an allen Typdeklarationen, also Klassen, Schnittstellen, Annotationstypen, Aufzählungen.

CONSTRUCTOR

an Konstruktor-Deklarationen

METHOD

an Deklarationen von statischen und nicht-statischen Methoden.

FIELD

an Deklarationen von statischen Variablen und Objekt-Variablen.

PARAMETER

an Parametervariablen von Methoden.

LOCAL_VARIABLE

an lokalen Variablen.

PACKAGE

an package-Deklarationen.

TYPE_PARAMETER

an der Deklaration einer Typ-Variablen für generische Typ-Parameter. Neu in Java 8. Wenn es etwa heißt class List<@AnAnnotation T>.

TYPE_USE

an allen Stellen, wo Typen eingesetzt werden, adressiert also Typ-Annotationen. Ebenfalls neu in Java 8. So etwas wie @NonNull (keine Annotation aus der Java SE!) ist ein Beispiel

Tabelle 1.3: ElementType bestimmt Orte, an denen Annotationen erlaubt sind.

Orte für Annotationen

Annotationen lasen sich setzen an allen Deklarationen und bei Typnutzungen (ab Java 8).

Deklarationen

Typnutzung

Typendeklarationen (Klassen, Schnittstellen, Aufzählungen, anderen Annotationtypen)

new-Operator

Eigenschaften (Konstruktoren, Methoden, Attributen)

Typ-Anpassung

 

implements-Klausel

 

throws-Klausel bei Methoden

Wo Annotationen möglich sind

Die Annotationen bei der Typnutzung nennen sich kurz Typ-Annotationen.

Java bringt einige Annotationstypen mit, doch die werden bisher ausschließlich für Deklarationen eingesetzt, wie das gekannte @Override. Vordefinierte Typ-Annotationen sind bisher in der Java SE nicht zu finden.

http://download.java.net/jdk8/docs/api/java/util/concurrent/locks/StampedLock.html

Neue Klasse in Java 8. Implementiert jedoch nicht Lock, wie es ReentrantLock tut. Aus der API:

A capability-based lock with three modes for controlling read/write access. The state of a StampedLock consists of a version and mode. Lock acquisition methods return a stamp that represents and controls access with respect to a lock state; "try" versions of these methods may instead return the special value zero to represent failure to acquire access. Lock release and conversion methods require stamps as arguments, and fail if they do not match the state of the lock. The three modes are:

  • Writing. Method writeLock() possibly blocks waiting for exclusive access, returning a stamp that can be used in method unlockWrite(long) to release the lock. Untimed and timed versions of tryWriteLock are also provided. When the lock is held in write mode, no read locks may be obtained, and all optimistic read validations will fail.
  • Reading. Method readLock() possibly blocks waiting for non-exclusive access, returning a stamp that can be used in method unlockRead(long) to release the lock. Untimed and timed versions of tryReadLock are also provided.
  • Optimistic Reading. Method tryOptimisticRead() returns a non-zero stamp only if the lock is not currently held in write mode. Method validate(long) returns true if the lock has not been acquired in write mode since obtaining a given stamp. This mode can be thought of as an extremely weak version of a read-lock, that can be broken by a writer at any time. The use of optimistic mode for short read-only code segments often reduces contention and improves throughput. However, its use is inherently fragile. Optimistic read sections should only read fields and hold them in local variables for later use after validation. Fields read while in optimistic mode may be wildly inconsistent, so usage applies only when you are familiar enough with data representations to check consistency and/or repeatedly invoke method validate(). For example, such steps are typically required when first reading an object or array reference, and then accessing one of its fields, elements or methods.

This class also supports methods that conditionally provide conversions across the three modes. For example, method tryConvertToWriteLock(long) attempts to "upgrade" a mode, returning a valid write stamp if (1) already in writing mode (2) in reading mode and there are no other readers or (3) in optimistic mode and the lock is available. The forms of these methods are designed to help reduce some of the code bloat that otherwise occurs in retry-based designs.

StampedLocks are designed for use as internal utilities in the development of thread-safe components. Their use relies on knowledge of the internal properties of the data, objects, and methods they are protecting. They are not reentrant, so locked bodies should not call other unknown methods that may try to re-acquire locks (although you may pass a stamp to other methods that can use or convert it). The use of read lock modes relies on the associated code sections being side-effect-free. Unvalidated optimistic read sections cannot call methods that are not known to tolerate potential inconsistencies. Stamps use finite representations, and are not cryptographically secure (i.e., a valid stamp may be guessable). Stamp values may recycle after (no sooner than) one year of continuous operation. A stamp held without use or validation for longer than this period may fail to validate correctly. StampedLocks are serializable, but always deserialize into initial unlocked state, so they are not useful for remote locking.

The scheduling policy of StampedLock does not consistently prefer readers over writers or vice versa. All "try" methods are best-effort and do not necessarily conform to any scheduling or fairness policy. A zero return from any "try" method for acquiring or converting locks does not carry any information about the state of the lock; a subsequent invocation may succeed.

Because it supports coordinated usage across multiple lock modes, this class does not directly implement the Lock or ReadWriteLock interfaces. However, a StampedLock may be viewedasReadLock(), asWriteLock(), or asReadWriteLock() in applications requiring only the associated set of functionality.

Java 8 – Alle Features komplett

Nach vielen Verzögerungen ist Java 8 nun Feature-komplett und befindet sich auf der (ziemlich langen) Zielgeraden. Voraussichtlich im März 2014 wird die neue Version mit der Unterstützung von Lambda-Ausdrücken in die Java-Geschichte eingehen. Lambda-Ausdrücke versprechen nicht nur klareren Code, sondern auch besser parallelisierbare Algorithmen. Daneben überzeugt Java 8 durch viele Detailverbesserungen und neue Bibliotheken.

Quelle: http://www.heise.de/developer/artikel/Was-Entwickler-mit-Java-8-erwartet-1932997.html