Inselraus: Echtzeit-Java (Real-time Java)

Zwar laufen bei der Java ME Programme auf Geräten mit reduziertem Speicher und eingeschränkter Prozessor-Leistungsfähigkeit, das sagt aber nichts über die Reaktionsfähigkeit der Laufzeitumgebung auf externe Ereignisse aus. Wenn ein Sensor in der Stoßstange einen Aufprall meldet, darf die Laufzeitumgebung keine 20 ms in einer Speicheraufräumaktion festhängen, bevor das Ereignis verarbeitet wird und der Airbag aufgeht. Um diese Lücke zu schließen, wurde schon früh – im Jahr 2001 – von der Java-Community die JSR 1, »Real-time Specification for Java« (kurz RTSJ), definiert (mittlerweile JSR 282 für den Nachfolger RTSJ 1.1.).

Echtzeit-Anwendungen zeichnen sich dadurch aus, dass es eine maximale deterministische Wartezeit gibt, die das System zum Beispiel bei der automatischen Speicherbereinigung blockiert, um etwa auf Änderungen von Sensoren zu reagieren – ein Echtzeitsystem kann eine Antwortzeit garantieren, etwas, was eine normale virtuelle Maschine nicht kann. Denn nicht nur die Zeit für die automatische Speicherbereinigung ist bei normalen Laufzeitumgebungen eher unbestimmt, auch andere Aktionen unbestimmter Dauer kommen dazu: Lädt Java eine Klasse, dann zur Laufzeit. Das kann zu beliebig vielen weiteren Abhängigkeiten und Ladezyklen führen. Bis also eine Methode ausgeführt werden kann, können Hunderte von Klassendateien nötig sein, und das Laden kann unbestimmt lange dauern.

Mit Echtzeitfähigkeiten lassen sich auch Industrieanlagen mit Java steuern und lässt sich Software aus dem Bereich Luft- und Raumfahrt, Medizin, Telekommunikation und Unterhaltungselektronik mit Java realisieren. Dieser Bereich blieb Java lange Zeit verschlossen und bildete eine Domäne von C(++). Damit dies in Java möglich ist, müssen JVM und Betriebssystem zusammenpassen. Während eine herkömmliche JVM auf mehr oder weniger jedem beliebigen Betriebssystem läuft, sind die Anforderungen an Echtzeit-Java strenger. Das Fundament bildet immer ein Betriebssystem mit Echtzeitfähigkeiten (Real-Time Operating System (RTOS)), etwa Solaris 10, Realtime Linux, QNX, OS-9 oder VxWorks. Darauf setzt eine Echtzeit-JVM auf, eine Implementierung der Real-Time-Spezifikation. Real-time Java (RT-Java) unterscheidet sich daher auch in Details, etwa dass Speicherbereiche direkt belegt und freigegeben werden können (Scoped Memory), dass mehr Thread-Prioritäten zur Verfügung stehen oder dass das Scheduling deutlich mehr in der Hand der Entwickler liegt. Die Entwicklung ist anders, findet aber unter den bekannten Werkzeugen wie IDEs, Testtools und Bibliotheken statt. In den letzten Jahren ist es allerdings um Real-time Java ruhig geworden.

Get the latest version of a maven groupId:artifactId via Node.js script

// npm install node-fetch
import fetch from 'node-fetch';
const groupId = "org.apache.maven.plugins";
const artifactId = "maven-compiler-plugin";
const url = `http://search.maven.org/solrsearch/select?q=g:"${groupId}"+AND+a:"${artifactId}"`;
const response = await fetch(url);
const body = await response.json();
const version = body.response.docs[0].latestVersion;
console.log(version);

 

Code Snippets in Java API Doku geplant (JEP 413)

Interessantes Feature, was die Javadoc doch dicker machen könnte. Geplant:

/**
 * The following code shows how to use {@code Optional.isPresent}:
 * {@snippet :
 * if (v.isPresent()) {
 *     System.out.println("v: " + v.get());
 * }
 * }
 */

Interessant wird das ganze durch Includes (wie bei Asciidoc):
/**
 * The following code shows how to use {@code Optional.isPresent}:
 * {@snippet file="ShowOptional.java" region="example"}
 */
Dinge können zum Beispiel fett hervorgehoben werden:
/**
 * A simple program.
 * {@snippet :
 * class HelloWorld {
 *     public static void main(String... args) {
 *         System.out.println("Hello World!");      // @highlight substring="println"
 *     }
 * }
 * }
 */
Und Texte können ersetzt werden:
/**
 * A simple program.
 * {@snippet :
 * class HelloWorld {
 *     public static void main(String... args) {
 *         System.out.println("Hello World!");  // @replace regex='".*"' replacement="..."
 *     }
 * }
 * }
 */

Ziemlich wild, würdet ihr so was nutzen für eure Javadoc? Ich nutzte bisher immer Testfälle, um eine API zu zeigen und auch zu lernen.

Zum Weiterlesen: https://openjdk.java.net/jeps/413

Inselraus: Vererbung und Überschattung von statischen Variablen in Schnittstellen

Die Konstanten einer Schnittstelle können einer anderen Schnittstelle vererbt werden. Dabei gibt es einige kleine Einschränkungen. Wir wollen an einem Beispiel sehen, wie sich die Vererbung auswirkt, wenn gleiche Bezeichner in den Unterschnittstellen erneut verwendet werden. Die Basis unseres Beispiels ist die Schnittstelle BaseColors mit ein paar Deklarationen von Farben. Zwei Unterschnittstellen erweitern BaseColors, und zwar CarColors und PlaneColors, die für Farbdeklarationen für Autos und Flugzeuge stehen. Eine besondere Schnittstelle FlyingCarColors erweitert die beiden Schnittstellen CarColors und PlaneColors, denn es gibt auch fliegende Autos, die eine Farbe haben können.

interface BaseColors {
  int WHITE   = 0;
  int BLACK   = 1;
  int GREY    = 2;
}
interface CarColors extends BaseColors {
  int WHITE   = 1;
  int BLACK   = 0;
}
interface PlaneColors extends BaseColors {
  int WHITE   = 0;
  int GREY    = 2;
}
interface FlyingCarColors extends CarColors, PlaneColors { }
public class Colors {
  public static void main( String[] args ) {
    System.out.println( BaseColors.GREY );      // 2
    System.out.println( CarColors.GREY );       // 2
    System.out.println( BaseColors.BLACK );     // 1
    System.out.println( CarColors.BLACK );      // 0
    System.out.println( PlaneColors.BLACK );    // 1
    System.out.println( FlyingCarColors.WHITE );
       //  field FlyingCarColors.WHITE is ambiguous
    System.out.println( FlyingCarColors.GREY );
       //  field FlyingCarColors.GREY is ambiguous
  }
}

Die erste wichtige Tatsache ist, dass unsere drei Schnittstellen ohne Fehler übersetzt werden können, aber nicht die Klasse Colors. Das Programm und der Compiler zeigen folgendes Verhalten:

  • Schnittstellen vererben ihre Eigenschaften an die Unterschnittstellen. CarColors und auch PlaneColors erben die Farben WHITE, BLACK und GREY aus BaseColors.
  • Konstanten dürfen überdeckt werden. CarColors vertauscht die Farbdeklarationen von WHITE und BLACK und gibt ihnen neue Werte. Wird jetzt der Wert BLACK verlangt, liefert die Umgebung den Wert 0, während BaseColors.BLACK 1 ergibt. Auch PlaneColors überdeckt die Konstanten WHITE und GREY, obwohl die Farben mit dem gleichen Wert belegt sind.
  • Erbt eine Schnittstelle von mehreren Oberschnittstellen, so ist es zulässig, dass die Oberschnittstellen jeweils eine gleichlautende Objektvariable haben. So erbt etwa FlyingCarColors von CarColors und PlaneColors die Einträge WHITE, BLACK und GREY.
  • Unterschnittstellen können aus zwei Oberschnittstellen die Objektvariablen gleichen Namens übernehmen, auch wenn die Konstanten einen unterschiedlichen Wert haben. Das testet der Compiler nicht. FlyingCarColors bekommt aus CarColors ein WHITE mit 1, aber aus PlaneColors das WHITE mit 0. Daher ist in dem Beispiel Colors auch der Zugriff WHITE nicht möglich und führt zu einem Compilerfehler. Bei der Benutzung muss ein unmissverständlich qualifizierter Name verwendet werden, der deutlich macht, welche Objektvariable gemeint ist, also zum Beispiel CarColors.WHITE oder PlaneColors.WHITE. Ähnliches gilt für die Farbe GREY. Obwohl Grau durch die ursprüngliche Deklaration bei BaseColors und auch bei der Überschattung in PlaneColors immer 2 ist, ist die Nutzung durch FlyingCarColors.GREY nicht zulässig. Das ist ein guter Schutz gegen Fehler, denn wenn der Compiler dies durchließe, könnte sich im Nachhinein die Belegung von GREY in BaseColors oder PlaneColors ohne Neuübersetzung aller Klassen ändern und zu Schwierigkeiten führen. Diesen Fehler – die Oberschnittstellen haben für eine Konstante unterschiedliche Werte – müsste die Laufzeitumgebung erkennen. Doch das ist nicht möglich, und in der Regel setzt der Compiler die Werte auch direkt in die Aufrufstelle ein, und ein Zugriff auf die Konstantenwerte der Schnittstelle findet nicht mehr statt.

Oracle JDK vs. OpenJDK und Migration zu Azul für den kommerziellen Betrieb

Veränderungen in der Verfügbarkeit des Java Development Kit seit dem Release des JDK 11 im September 2018 erschweren den sicheren Betrieb von Java-Anwendungen für viele Endnutzer. Die Nutzung des Oracle JDK ist im kommerziellen IT Betrieb nun nur noch mit Lizenz möglich.
Azul Systems tritt an, mit der Zulu OpenJDK Laufzeitumgebung eine wirtschaftlich attraktive Java-Distribution mit zuverlässigen Updates und Bug Fixes anzubieten.

2006 hat Sun Microsystems, zu diesem Zeitpunkt der Inhaber der Marke Java, angekündigt das JDK in ein Open-Source Projekt zu überführen. Zu diesem Zweck wurde das OpenJDK Projekt in Leben gerufen, das ein Zuhause auf http://openjdk.java.net fand. Beginnend mit dem JVM Source Code wurden bis Anfang 2007 auch die Kernbibliotheken veröffentlicht. Einige Teile des OpenJDK blieben bis April 2009 proprietär, bis mit build 53 des OpenJDK 7 eine vollständig auf Open Source basierende Distribution verfügbar war. Seit Java 7 SE ist das OpenJDK die Referenzimplementierung des Java SE-Standards, der durch die entsprechenden Java Specification Requests (JSR) festgelegt wird. Ein Projekt mit dem Ziel einer Open Source Umsetzung von Java SE 6 wurde ebenfalls gestartet, geleitet von Andrew Brygin von Azul Systems. Das OpenJDK steht unter der GNU Public License (GPL) version 2 with classpath exception (CPE). Die Lizenzierung unter der CPE verhindert das die „copyleft“ Natur der GPL sich auf die Anwendungen auswirkt die das OpenJDK als Laufzeitumgebung nutzen. Im September 2007 hat Oracle zahlreiche Veränderungen bei der Art und Weise wie das JDK entwickelt, verbreitet und aktualisiert wird. Diese lassen sich wie folgt zusammenfassen:

  • Der Releasezyklus des JDK ist kalendergetrieben mit zwei Releases pro Jahr im März und September.
  • Oracle hat liefert nun eine zweite Binärdistribution des JDK aus, die ausschließlich auf OpenJDK Source Code basiert. Diese wird unter der GPLv2 with classpath exception license verbreitet, die weniger restriktiv als die Oracle Binary Code License (BCL) for Java SE ist, welche für Oracle Binaries verwendet wird.
  • Ab JDK 11 gibt es keine funktionalen Unterschiede mehr zwischen den Oracle JDK Binaries und eine reinen Open Source OpenJDK. Um dies zu ermöglichen, hat Oracle einige zuvor proprietäre Features zum OpenJDK hinzugefügt (z.B. Mission Control und Flight Recorder). Einige andere Features, wie Web Start und JavaFX, wurden entfernt.
  • Ab JDK 11 nutzt Oracle das Oracle Technology Network License Agreement (OTNLA) welches keine völlig freie Nutzung mehr erlaubt. Unter dieser Lizenz kann das Oracle JDK frei für Entwicklung und Test verwendet werden, benötigt aber eine kommerzielle Lizenz für die produktive Nutzung.
  • Oracle OpenJDK-Binaries werden nur maximal 6 Monate bis zum nächsten JDK gepflegt. Longterm Support ist von Oracle nur unter einem Lizenzvertrag verfügbar sein.
  • Freie Updates für das JDK 8 enden im Januar 2019 mit Update 202. Anwender können dies Version frei weiter nutzen, da sie noch unter der Oracle BCL steht. Ab April 2019 stehen die Updates auf java.oracle.com unter der OTNLA und bedürfen zur produktiven Nutzung eine Lizenzvereinbarung mit Oracle.

Das OpenJDK ist ein reines Source Code Projekt. Um es als Java Laufzeitumgebung nutzen zu können ist es nötig, das Projekt in eine Binärdistribution zu kompilieren. Die von Azul erstellte Distribution trägt den Namen Zulu. Zulu wird, mit dem vom OpenJDK vorgegebenen Standard
Build Prozess erstellt und alle Binaries mit dem Technology Compatibility Kit (TCK) validiert, um Kompatibilität und Konformität mit der Java SE-Spezifikation sicherzustellen. Um die den stabilen und sicheren Betrieb bei den Kunden zu ermöglichen werden regelmäßige Updates für
das OpenJDK erstellt, die Bug Fixes und Security Patches enthalten. Bis zu Version 9 des JDK wurden diese Updates jeweils für die aktuelle Version und die vorhergehende Version bereitgestellt. Die Überlappung der Supportzeiträume seit JDK 6 betrug zwischen 13 und 37 Monate. Unter der neuen Release Policy sind jedoch bereits OpenJDK 6, 7, 8 und 11 aus dem öffentlichen und freien Support herausgefallen. Azul liefert auf weiterhin Updates für all diese JDK-Versionen. Dies erlaubt es den Kunden auch ältere Java-Versionen sicher im produktiven Betrieb zu nutzen.

Unterschiede zwischen OpenJDK und Oracle JDK

Da das OpenJDK die Referenzimplementierung des Java SE-Standards darstellt, nutzen Oracle und andere es als Basis ihrer Binärdistributionen. Vor JDK 11 enthielt das Oracle JDK eine Reihe von
zusätzlichen Features, von denen einige nun Open Source sind, andere bleiben proprietär.

  • Die Kryptographie-Module von Oracle JDK und OpenJDK unterstützten die gleichen kryptographischen Funktionen auf der Basis des gleichen Source-Codes. Ab Januar 2018 (JDK 8 Update 161) haben alle OpenJDK-basierten Distributionen (Zulu und Oracle) Einschränkungen zur Schlüssellänge und Stärke der Verfahren entfernt. Zuvor war die Schlüssellänge auf 128 Bit beschränkt, und es war nötig, ein ergänzendes Modul zu installieren, um starke Kryptographie zu aktivieren. Für Oracle JDK war dieses Module das Java Cryptographic Extensions (JCE) package, und für Zulu, das Cryptographic Extension Kit (CEK). Zulu und Oracle JDK folgen im Allgemeinen der gleichen Kryptographie-Roadmap. Details siehe Link https://www.java.com/en/jre-jdk-cryptoroadmap.html.
  • JavaFX ist ein optionales GUI Framework, welches Oracle mit dem JDK ausgeliefert hat. Die Quellen wurden in das OpenJFX-Projekt überführt. Azul unterstützt OpenJFX im ZuluFX Bundle. Download verfügbar unter: http://openjdk.java.net/projects/openjfx
  • Browser-Plugin: Das Browser Applet Plugin ist mit dem Oracle JDK, aber nicht mit Zulu JDK verfügbar.
  • Applet-Support im Browser wurde mit JDK 9 deprecated und mit JDK 11 von Oracle entfernt.
  • Java Web Start: Im Oracle JDK enthalten, aber nicht im Zulu JDK. Azul bietet mit IcedTea-Web eine Open Source Alternative. Java WebStart wurde wie Applets mit JDK deprecated und in JDK 11 entfernt. IcedTea-Web ist auch für Zulu 11 verfügbar. Für IcedTea-Web ist ein sorgfältiger
    Migrationstest notwendig.
  • Mission Control: Bis Oracle JDK 9 ist Mission Control ein kostenpflichtiges Add-on für den produktiven Betrieb. Mission Control ist seit JDK 10 Open Source und Teil des OpenJDK. Azul stellt Mission Control als separates Paket bereit. Es ist mit jeder JVM mit Flight Recorder Unterstützung kompatibel.
  • Flight Recorder: Wie Mission Control war der Flight Recorder bis JDK 10 kostenpflichtig, ab JDK 11 Open Source. Azul hat einen Backport auf Zulu 8 erstellt, so dass Azul-Kunden ab Zulu 8 (update 202) von Mission Control Unterstützung profitieren können.
  • – VisualVM: Bis JDK 8 Teil des Oracle JDK, aber nicht Teil von Zulu. VisualVM wurde ab JDK 9 entfernt , ist aber weiterhin als separates Open-Source-Projekt verfügbar: https://visualvm.github.io/.
  • Java DB: Binärdistribution der Apache Derby Datenbank, die im Oracle JDK bis JDK 8 enthalten war, aber nicht mit Zulu ausgeliefert wurde. Ab JDK 9 entfernt, aber weiterhin als Open Source Projekt verfügbar: https://db.apache.org/derby/.

Nicht im OpenJDK enthaltene Features

  • Fonts: Sowohl Oracle als auch Zulu JDKs werden mit dem gleichen Satz an kommerziell lizenzierten Fonts ausgeliefert.
  • SNMP: Das Oracle JDK enthält ein proprietäres Modul. Diese wurde mit JDK 11 aus dem Oracle JDK entfernt. Die Open Source Lösung SNMP4J  http://snmp4j.com/ kann ggf. als Alternative dienen.
  • Sound-Treiber: Nur für ältere Windows Versionen benötigt und nicht im OpenJDK enthalten.

Abweichungen zwischen OpenJDK und Oracle JDK

  • Color Matching: Das Oracle JDK verwendet eine proprietäre Lösung. Zulu JDK nutzt die Lösung des OpenJDK, die vergleichbare, aber nicht identische Ergebnisse liefert.
  • Font Rendering: Das Oracle JDK verwendet einen proprietären Font-Renderer (T2K). Zulu (und OpenJDK) nutzen den FreeType Open Source Renderer https://www.freetype.org/.
  • Java 2D Graphics Rasterizer: Vor JDK 9 nutzte OpenJDK den Pisces Open Source Renderer, während Oracle JDK ein proprietäres Modul, Ductus, verwendete. Ab JDK 9 wurde Pisces durch den Marlin Renderer ersetzt, dessen Performance mit Ductus vergleichbar ist. Zulu JDK nutzt Marlin seit JDK 8.

JDK Deployment

Anwender können bei der Planung des OpenJDK-Rollout folgenge Option in Betracht ziehen:

  • Weiternutzung der bereits installierten Java-Laufzeitumgebungen, wie z. B. JDK 8, ohne Updates und Security-Patches. Dies ist die Option mit dem höchsten betrieblichen Risiko, da im Laufe der Zeit vermehrt Sicherheitslücken aufgedeckt werden. Für Anwendungen die regulatorischen Anforderungen entsprechen müssen ist dies ein erhebliches Problem.
  • Migration der Anwendungen auf die neueste freie OpenJDK-Version mit Update auf die Folgeversion alle 6 Monate. Dies ist mit einem Kompatibilitätsrisiko verbunden, da Oracle angekündigt hat, das Kompatibilität nicht mehr 100% garantiert wird (bis JDK 9 war Rückwärtskompatibilität stehts ein Designziel). Der Test und Migrationsaufwand kann für nicht aktiv weiterentwickelte Anwendungen erheblich sein.
  • Weiterverwendung von Oracle JDK als kostenpflichtige Subskription. Dies eliminiert die Risiken der vorgenannten Optionen ist aber meist die teuerste Lösung. Die neue Oracle Java Subskription wird auf der Basis von „Oracle Processors“ kalkuliert. Die Ermittlung der zu lizensierenden Mengen kann komplex sein, da neben der genauen Zahl von physischen Cores ein CPU Typ spezifischer „Core factor“ herangezogen werden muss. In virtualisierten Umgebungen (z. B. VMware) muss das gesamte vCenter lizensiert werden, da Applikationen zwischen Servern migrieren können. Ein typischer Server hat zwei Intel Xeon Hexa-core CPUs und wird als sechs „Oracle Processors“ gezählt. Bei Java SE-Subskriptionskosten von $25 pro Oracle Processor pro Monat sind dies $1800 pro Jahr für diesen Beispielserver. In Umgebungen mit über 1000 Servern können die Kosten über einer Million USD pro Jahr liegen.
  • Support für eine alternativen OpenJDK Variante mit niedrigeren Gesamtkosten. Azul kann mit der Zulu Enterprise Distribution eine attraktives Angebot machen, da nur die Zahl der physischen Server in Betracht gezogen werden, und es bei über 1000 Servern zu weniger als einem Zehntel des Oracle Subskription Listenpreises kommt. Für größere Umgebungen ist daher Zulu Enterprise immer die kostengünstigere Lösung.

Migration zu Zulu Enterprise

Das Zulu OpenJDK wird unter der GPLv2 with CPE Lizenz veröffentlicht. Zulu Binaries stehen für Windows, Linux, Solaris und MacOS X auf https://www.azul.com/downloads/zulu-community/ zum Download bereit. Auch Release Notes mit Installationsanleitung finden sich auf dieser Seite. Diese decken alle bereitgestellten Paketformate, Abhängigkeiten sowie Anleitungen für die Installation in gängigen Cloud Umgebungen wie Microsoft Azure und Amazon Web Services bereit. Enthalten sind auch Post-Installationsschritte und eine Anleitung wie die Standard Java Runtime auf einem Server/Desktop aus festgelegt werden kann.

Das Zulu Commercial Compatibility Kit

Die proprietären Lucida Font aus dem Oracle JDK sind nicht Teil des Standard OpenJDK. Falls erforderlich stellt das Zulu Commercial Compatibility Kit (CCK)diese Fonts bereit, um in GUIs und PDF Generatoren ein identisches Layout und Schriftbild zu erhalten.

Zum Download des Zulu CCK müssen die Nutzungsbedingungen akzeptiert werden. Der Installer überprüft, ob eine passende Zulu-Version installiert ist. Beim Download ist auf die korrekte Version zu achten! Details und Download gibt es unter https://www.azul.com/products/zulu-and-zulu-enterprise/cck-downloads/. Dies ermöglicht in der Regel eine Migration ohne zusätzlich betriebliche Aufwände.

Zusammenfassung

Zulu ist eine OpenJDK Distribution die vollumfänglich der Java SE-Spezifikation entspricht. Jede Anwendung, die auf Standard Java-Komponenten und APIs setzt, kann durch einen einfachen Austausch des JDK Pfads migriert werden. Ein engagiertes Entwicklerteam nimmt komplexe Anpassungen, wie Backporting und Integration von Updates in ältere OpenJDK-Versionen vor; daher können sich Azul-Kunden der aktuellsten Security-Patches und Bug-Fixes auch auf älteren Java-Versionen erfreuen.

Die Zulu OpenJDK-Distribution bietet eine kostengünstige Alternative, um Applikationen auf aktuelle Java Versionen zu migrieren und sicher zu betreiben.

Quiz: Listen in Arrays konvertieren und toArrays(…) beherrschen

Während Array.asList(...) nur ein Dektorator ist, der ein Array so aussehen lässt, als wäre es eine List, übertragen drei überladene Methoden toArray(...) aus Collection alle Elemente einer Sammlung auf eine Liste:

  • Object[] toArray()
  • <T> T[] toArray(T[] a)
  • default <T> T[] toArray​(IntFunction<T[]> generator) (Java 11)

Was ist das Ergebnis der Ausgabe?

List<String> list = new ArrayList<>( Arrays.asList( "a", "b" ) );
System.out.println( list.toArray()[ 0 ] );
System.out.println( list.toArray( new String[ 0 ] )[ 0 ] );
System.out.println( list.toArray( new String[ 0 ] ).length );
System.out.println( list.toArray( new String[ 1 ] )[ 0 ] );
System.out.println( list.toArray( new String[ 1 ] ).length );
System.out.println( list.toArray( value -> new String[ 1 ] )[ 0 ] );
System.out.println( list.toArray( value -> new String[ 1 ] ).length );
System.out.println( list.toArray().getClass() );
System.out.println( list.toArray( new String[ 0 ] ).getClass() );

Lösung .

.

.

.

.

.

.

.

.

.

.

.

.

.

.

List<String> list = new ArrayList<>( Arrays.asList( "a", "b" ) );
System.out.println( list.toArray()[ 0 ] ); // a
System.out.println( list.toArray( new String[ 0 ] )[ 0 ] ); // a
System.out.println( list.toArray( new String[ 0 ] ).length ); // 2
System.out.println( list.toArray( new String[ 1 ] )[ 0 ] ); // a
System.out.println( list.toArray( new String[ 1 ] ).length ); // 2
System.out.println( list.toArray( value -> new String[ 1 ] )[ 0 ] ); // a
System.out.println( list.toArray( value -> new String[ 1 ] ).length ); // 2
System.out.println( list.toArray().getClass() ); // class [Ljava.lang.Object;
System.out.println( list.toArray( new String[ 0 ] ).getClass() ); // class [Ljava.lang.String;

Es hilft beim Verständnis sich den Code aus dem OpenJDK anzuschauen:

Aus der OpenJDK-Implementierung von java.util.ArrayList:

public Object[] toArray() {
return Arrays.copyOf( elementData, size );
}

Aus der OpenJDK-Implementierung von java.util.ArrayList:

public T[] toArray( T[] a ) {
if ( a.length < size ) // Make a new array of a’s runtime type, but my contents: return (T[]) Arrays.copyOf( elementData, size, a.getClass() ); System.arraycopy( elementData, 0, a, 0, size ); if ( a.length > size )
a[ size ] = null;
return a;
}

Aus der OpenJDK-Implementierung von java.util.Collection:

default T[] toArray( IntFunction generator) {
return toArray(generator.apply(0));
}

 

Geschichte hinter OpenJDK

Schon seit Java 1.0 gibt es den Quellcode der Standardbibliotheken (falls er beim JDK mitinstalliert wurde, befindet er sich im Wurzelverzeichnis unter dem Namen src.zip), und jeder Interessierte konnte einen Blick auf die Implementierung werfen. Zwar legte Sun damals also die Implementierungen offen, doch weder die Laufzeitumgebung noch der Compiler oder die Bibliotheken standen unter einer akzeptierten Open-Source-Lizenz. Zehn Jahre seit der ersten Freigabe von Java gab es Forderungen an Sun, die gesamte Java-Plattform unter eine bekanntere Lizenzform wie die GNU General Public License (GPL) oder die BSD-Lizenz zu stellen. Dabei deutete Jonathan Schwartz in San Francisco bei der JavaOne-Konferenz 2006 schon an: »It’s not a question of whether we’ll open source Java, now the question is how.« War die Frage also statt des »Ob« ein »Wie«, kündigte Rich Green bei der Eröffnungsrede der JavaOne-Konferenz im Mai 2007 die endgültige Freigabe von Java als OpenJDK (http://openjdk.java.net/) unter der Open-Source-Lizenz GPL 2 an. Dem war Ende 2006 die Freigabe des Compilers und der virtuellen Maschine vorausgegangen.

Obwohl OpenJDK unter der GPL stand, enthielt es doch Teile wie den Font-Renderer, Sound-Unterstützung, Farbmanagement oder SNMP-Code, die als binäre Pakete beigelegt wurden, weil etwa die Rechte zur Veröffentlichung fehlten. Sun nennt diese Teile, die etwa 4 % vom JDK 6 ausmachen, belasteten Code (engl. encumbered code). Das hinderte puristische Linux-Distributoren daran, OpenJDK auszuliefern. RedHat startete im Juni 2007 das Projekt IcedTea, um diese binären Teile auf der Basis des OpenJDK durch GPL-Software zu ersetzen. So basiert der Font-Renderer zum Beispiel auf FreeType und das Farbmanagement auf little CMS. Mit diesen Ersetzungen erfüllte das OpenJDK mit IcedTea im Juni 2008 die Anforderungen des Technology Compatibility Kit (TCK) von Sun und ist in der Öffentlichkeit seither unter dem Namen OpenJDK 6 bekannt. Daraufhin floss das OpenJDK 6 plus der Ersetzungen unter der GPLv2 in Linux-Distributionen wie Fedora und Debian ein.

Das OpenJDK bildet die Basis von Java 8, und jeder Entwickler kann sein eigenes Java zusammenstellen und beliebige Erweiterungen veröffentlichen. Damit ist der Schritt vollzogen, dass auch Java auf Linux-Distributionen Platz finden darf, die Java vorher aus Lizenzgründen nicht integrieren wollten.

Auch wenn es sich so anhört, als ob das Oracle JDK bzw. OpenJDK das Gleiche sei, ist das nicht ganz richtig: Zwar basieren Oracle JDK und OpenJDK auf den gleichen Quellen (bei der Version 7 etwa zu 95 %), doch sind beim Oracle JDK immer noch proprietäre Dinge enthalten, und nicht alles ist hundertprozentig quelloffen und GPL. Das gilt für die Version 7 wie für die Version 6. Das Oracle JDK steht unter der Binary Code License; genau die muss jeder abnicken, der das JDK von der Webseite laden möchte.

Bei der 6er-Reihe kommt noch eine Besonderheit dazu, wie es die Versionsnummern ganz gut zeigen. Während das Oracle JDK zum Beispiel im Juni 2011 bei Versionsnummer 1.6.0_26-b03 steht, ist das OpenJDK bei Version 6 b22. Die Versionsnummern sind deshalb völlig unabhängig, weil beide Projekte auch unabhängig voneinander laufen. Das hat mit der Geschichte zu tun. Nach der Entwicklung des JDK 6, das nicht unter der GPL steht, ging es mit dem JDK 7 logisch weiter. Aus dem JDK 7 (Build 10) entstand dann OpenJDK, das heute mit der Versionsnummer OpenJDK 7 genannt wird. OpenJDK 7 und JDK 7 entwickeln sich Hand in Hand, und Code-Änderungen gehen mal in die eine Richtung und mal in die andere.

Jetzt kommt die Besonderheit: Das OpenJDK 6 entstand nicht, wie vermutet werden könnte, aus dem Oracle JDK 1.6, sondern aus dem OpenJDK 7 (Build 20). Es wurden nur Java 7-Eigenschaften entfernt: Die meisten Patches am OpenJDK 6 sind Backports von OpenJDK 7. Änderungen am OpenJDK 7 stammen überwiegend von Oracle, und häufig ist es die Firma Red Hat, die diese Änderungen in OpenJDK 6 portiert. Zwischen dem OpenJDK 6 und dem JDK 1.6 gibt es einen Quellcodeaustausch bei Bug-Fixes, doch die Codebasis ist unterschiedlich. Oracle JDK 6 ist im Wartungsmodus, und großartige Veränderungen passieren bis auf Fehlerbereinigungen nicht.

Oracle JDK 8 ist die Version, die die Download-Seite von Oracle anbietet; das OpenJDK 8 liegt auf einem eigenen Server http://openjdk.java.net/projects/jdk8/. Das OpenJDK bildet die Referenzimplementierung für Java SE, nicht das Oracle JDK.

OpenJDK

Das freie und unter der GPL stehende OpenJDK (http://openjdk.java.net/) bildet nunmehr die Referenzimplementierung für Java SE. Alle Entwicklungen finden dort statt. Der Fortschritt ist live zu beobachten, regelmäßig fixen und erweitern Hunderte von Entwicklern die Codebasis. Die Quellen für das OpenJDK lassen sich im Mercurial-Repository unter http://hg.openjdk.java.net/jdk/jdk14 einsehen (ein Wechsel auf GitHub wird diskutiert). Viele Technologien, die Oracle vorher nur im Oracle JDK hatte, wurden in das OpenJDK übertragen, etwa Java Flight Recorder, Java Mission Control, Application Class-Data Sharing und ZGC (Zero-Garbage-Collector).

OpenJDK-Builds von Oracle

Oracle selbst compiliert das OpenJDK und bietet es an. Aktuelle Versionen sind über http://jdk.java.net/ verlinkt. Es gibt von Oracle OpenJDK-x64-Builds für Windows, Linux und macOS.

Das Oracle OpenJDK steht unter der GNU General Public License v2 mit der Classpath Exception (GPLv2+CPE). Oracle selbst hat angekündigt, bei neuen Versionen keine Updates mehr für die alten Versionen zu veröffentlichen.

OpenJDK-Builds von AdoptOpenJDK

AdoptOpenJDK (https://adoptopenjdk.net/) ist eine Stiftung und betreibt eine Serverfarm, die regelmäßig Builds vom OpenJDK baut und dazu weitere Software wie die JavaFX-Implementierung OpenJFX und alternative Laufzeitumgebungen wie Eclipse OpenJ9 einbindet. Es wird angekündigt, auch ältere Versionen mit Bugfixes zu versorgen. Zu den Unterstützern zählen Amazon, IBM/Red Hat, Microsoft, Pivotal und viele weitere.

Von der Webseite lässt sich für unterschiedliche Betriebssysteme eine Version herunterladen. Angeboten werden Builds u.a. für: Windows, Linux, macOS.

AdoptOpenJDK zählt aktuell zu den populärsten OpenJDK-Distributionen.

Weitere OpenJDK-Builds

Das Unternehmen Azul bietet Builds unter dem Namen Zulu an, auch lässt sich ein Support-Vertrag abschließen: http://www.azul.com/downloads/zulu/. Neben den Plattformen Windows, Linux und macOS gibt es von Azul ebenfalls Docker-Images.

Red Hat bietet neben Linux auch eine Windows-Version vom OpenJDK an: http://developers.redhat.com/products/openjdk/overview/. Die Integration in Linux ist sehr gut, und Red Hat pflegt auch noch Sicherheitsupdates in Java 6 und Java 7 ein.

SAP bietet mit der SapMachine (http://sap.github.io/SapMachine/) Builds für diverse Betriebssysteme und auch ein Docker-Image.

Amazon Corretto (http://aws.amazon.com/de/corretto/) wird intern von Amazon in der Cloud eingesetzt und ist für die LTS-Versionen Java 8 und Java 11 kostenlos.

Alibaba Dragonwell (http://github.com/alibaba/dragonwell8) ist eine vom OpenJDK 8 abgeleitete Implementierung von Alibaba.

Von BellSoft gibt es das Liberica JDK (http://bell-sw.com/) für die Plattformen Windows x86_64 und auch noch Windows x86, macOS x86_64, Linux x86_64, Linux ARMv8, Linux ARMv7 HardFloat, Solaris SPARC und Solaris x86_64.

Apple pflegte lange Zeit eine komplett eigene JVM, bis Apple den Code an Oracle für das OpenJDK übergab. Auch Google setzt bei Android neuerdings auf das OpenJDK.

Oracle JDK

Oracle vermarktet auf der Basis des OpenJDK sein eigenes Projekt, Oracle JDK. Ab Java 11 sind das Oracle JDK und OpenJDK vom Code her (nahezu) identisch. Das Oracle JDK ist die »offizielle« Version, die die Java-Download-Seite von Oracle anbietet. Wenige kleine Unterschiede sind die Paketierung (das Oracle JDK hat einen Installer, das Oracle OpenJDK ist nur ein ZIP), die Versionskennung und ein paar weitere Module.[1]

Long Term Support (LTS)

Die halbjährlichen Java-Releases haben zur Folge, dass Versionen immer dann veraltet sind, wenn eine neue Version erscheint. In dem Moment, in dem Java 10 kam, war Java 9 veraltet; das Gleiche gilt bei Java 14 – es machte sofort Java 13 zur alten Version. Das allein wäre kein Problem, wenn die älteren Versionen mit Sicherheitsupdates versorgt würden. Aber Oracle investiert für die Allgemeinheit keine Zeit und Mühe mehr und pflegt die alten Versionen nicht.

Für Unternehmen ist das ein Problem, denn es erzeugt Stress, mit den Änderungen mitziehen zu müssen. Aus diesem Grund bietet Oracle alle drei Jahre eine Java-Version mit Long Term Support (LTS) und versorgt sie mit Updates und Sicherheitspatches. Die LTS-Versionen nach Java 8 sind Java 11 (September 2018) und dann nach 3 Jahren Java 17 (September 2021). Das ist für weniger agile Unternehmen gut. Oracle will seine Java SE 8-Implementierung noch viele Jahre pflegen.

Kommerzialisierung des Oracle JDK

Auf den ersten Blick sieht das gut aus: Es gibt regelmäßige Updates für agile Unternehmen, und die konservativen Unternehmen setzen auf eine LTS-Version. Das Problem ist allerdings, dass alle Oracle JDK-Versionen nicht kommerziell eingesetzt werden dürfen; der Hersteller erlaubt die Nutzung nur für »development, testing, prototyping or demonstrating purposes«.

Für Java 8 endete die Schonfrist im Januar 2019. Das dürfte vielen Entwicklern gar nicht bewusst sein, denn seit 20 Jahren sind Unternehmen daran gewöhnt, das Oracle JDK für alles einzusetzen. Und wir wissen alle, wie viele Menschen wirklich die Lizenzbedingungen lesen …

Wer also das Oracle JDK kommerziell einsetzen möchte und nicht nur in einer Entwicklungs- oder Testumgebung, muss eine Lizenz von Oracle erwerben. Es wird monatlich abgerechnet, die Vertragslaufzeit beträgt mindestens ein Jahr. Es stehen zwei Modelle zur Auswahl:

Java SE SubscriptionJava SE Desktop Subscription
Für ServeranwendungenFür Client-Anwendungen
Abrechnung pro ProzessorAbrechnung pro Benutzer
Bis 25 USD/Monat, für 1–99 BenutzerBis 2,50 USD/Monat für 1–999 Benutzer/Clients
Zwei Lizenzmodelle für Oracle Java SE

Oracle wendet bei der Java SE Subscription das gleiche Geschäftsmodell wie bei der Oracle-Datenbank an. Wie genau ein Rechner in der Cloud mit einer unbestimmten Anzahl der Prozessoren abgerechnet werden soll, ist noch unklar.[2] Interessenten sollten die »Oracle Java SE Subscription FAQ« unter http://www.oracle.com/technetwork/java/javaseproducts/overview/javasesubscriptionfaq-4891443.html studieren und Oracle-Berater hinzuziehen. Wer Client- und Serveranwendungen nutzt, muss zweimal bezahlen. Statt »write once, run anywhere« heißt es nun »write once, pay everywhere«.

Die Kosten können sich schnell summieren, doch bekommen Unternehmen damit Support und insbesondere für Java 8 immer noch für einige Jahre Unterstützung. Der Nachteil ist, dass es das Subscription-Modell nur für die LTS-Versionen gibt, Unternehmen also gezwungen werden, größere Versionssprünge zu machen. Nach Java 11 kommt erst im September 2021 die Version Java 17 mit dem nächsten LTS.

Quarkus 1.0.0 erschienen

Das „Kubernetes Native Java stack tailored for OpenJDK HotSpot and GraalVM, crafted from the best of breed Java libraries and standards.“ ist in der ersten Version erschienen und positioniert sich gegen Spring Boot und Jakarata EE.

Zum Weiterlesen und schauen:

Microsoft arbeitet am OpenJDK mit

https://mail.openjdk.java.net/pipermail/discuss/2019-October/005173.html:

Subject: Microsoft’s Ready do Contribute to OpenJDK

Hi OpenJDK Community,

In the past week Microsoft formally signed the Oracle Contributor Agreement, in which Oracle Inc. promptly acknowledged and welcomed us to the project. On behalf of the Microsoft Java Engineering Team, I’d like to say that we are thrilled to officially join the OpenJDK project and be ready to work with you.

As many of you may know, Microsoft and its subsidiaries are heavily dependent on Java in many aspects, and also offers Java runtimes in its Microsoft Azure cloud to its customers. Microsoft recognizes the immense value that Oracle’s successful and effective stewardship of the OpenJDK project has bought Java and the wider software ecosystem and we look forward to playing our part in contributing back!

The team will initially be working on smaller bug fixes and backports so that we can learn how to be good citizens within OpenJDK. For example, we already understand that discussing changes first before posting patches is preferred and I'm sure there's more for us to learn as well.

The Java engineering team led by Martijn Verburg [1] is already engaged with other Microsoft groups and its subsidiaries who are using Java, as well as its partners in the Java ecosystem such as Azul Systems, Oracle, Pivotal, Red Hat, Intel, SAP and others, and the overall team will be joining the many OpenJDK mailing lists to start conversations and participating.

We look forward to participating in the future of Java.

[1] martijn.verburg at microsoft.com<mailto:martijn.verburg at microsoft.com>

Best regards
Bruno Borges
Product Management for Java,
Microsoft Developer Division

Mehr zu der Geschichte unter

  • https://jaxenter.com/microsoft-ready-contribute-openjdk-163550.html

JDK 13 ist in Release Candidate Phase

Laut https://mail.openjdk.java.net/pipermail/jdk-dev/2019-August/003250.html:

Per the JDK 13 schedule [1], we are now in the Release Candidate phase.
The stabilization repository, jdk/jdk13, is open for P1 bug fixes per
the JDK Release Process (JEP 3) [2].  All changes require approval via
the Fix-Request Process [3].

If you’re responsible for any of the bugs on the RC candidate-bug list
[4] then please see JEP 3 for guidance on how to handle them.

We’ll tag the first Release Candidate build shortly.

- Mark


[1] https://openjdk.java.net/projects/jdk/13/#Schedule
[2] https://openjdk.java.net/jeps/3
[3] https://openjdk.java.net/jeps/3#Fix-Request-Process
[4] https://j.mp/jdk-rc

Weiteres unter http://www.tutego.de/java/jdk-13-java-13-openjdk13.html.

Google Guava 28.0 erschienen

Änderungen laut https://github.com/google/guava/releases/tag/v28.0:

  • collect: Added Duration-based overloads to some Queues methods. (21d06cf)
  • net: Added MediaType for „application/geo+json“. (36cd5cf)
  • net: Added a number of constants to HttpHeaders.
  • concurrent: Removed deprecated CheckedFuture and related utilities. (3dd22fe)
  • concurrent: Added Duration-based overloads to many methods.
  • concurrent: Removed @Beta from setFuture. (5ec1360)
  • concurrent: Added deprecated FluentFuture.from(FluentFuture) to point out redundant code. (f9f2807)
  • graph: Added GraphBuilder.immutable(),ValueGraphBuilder.immutable() and NetworkBuilder.immutable() for building immutable graphs in a fluent way.
  • J2ObjC: Fixed crashes from use of ImmutableMap.entrySet(). (74fc49f)