Suche
Teil 1: Ein Überblick

Java 7: The Big Update

Angelika Langer, Klaus Kreft

Es ist soweit: Java 7 wurde offiziell freigegeben. Wir wollen in diesem Beitrag einen Überblick über die Neuerungen geben und uns einige der neuen Sprachmittel und JDK-Ergänzungen in den nachfolgenden Beiträgen genauer ansehen.

Die Version 7 von Java hat lange auf sich warten lassen. Das liegt unter anderem daran, dass im Januar 2010 Sun Microsystems vom Softwarekonzern Oracle übernommen wurde und damit die Verantwortung für Java und den JDK an Oracle übergegangen ist. Wie vermutlich jede Firmenübernahme führte es zu Neuorientierungen, Umorganisationen und allerlei strategischen und organisatorischen Neuausrichtungen, die in diesem Fall die Freigabe der Version 7 von Java beeinflusst und verzögert haben.

Aber auch schon vor dieser Firmenübernahme war Java 7 in keinem überzeugenden Zustand. Der Community Process (JCP), in dem bis dahin die wesentlichen Weiterentwicklungen von Java besprochen, spezifiziert und verabschiedet worden waren, hatte sich seltsam aufgelöst. Das dürfte wesentlich an den Streitigkeiten zwischen der Apache Software Foundation und Sun Microsystems im Zusammenhang mit dem Apache Harmony JDK gelegen haben. Aber auch verschiedene technische Themen waren extrem umstritten in der Java-Community – Closures/Lambdas und die Modularisierung gehören zu diesen Streitpunkten. Die Meinungsverschiedenheiten hatten dazu geführt, dass es zwar Implementierungen für einige Neuerungen gab, aber keinerlei Konsens und auch keine Spezifikation dessen, was implementiert worden war. Das Ergebnis war ein JDK 7, nämlich der OpenJDK, zu dem Sun Microsystems die maßgeblichen Beiträge geleistet hat. Aber es gab kein Java 7, also keine Festlegung dessen, was eigentlich die Version 7 von Java ausmacht. Interessanterweise gab es aber einen (noch von Sun Microsystems veröffentlichten) Meilensteinplan, in dem die Freigabe von Java 7 für den 9. September 2010 angekündigt war. Genau an diesem Stichtag sah sich Oracle dann veranlasst zu verkünden, dass es leider zu diesem Zeitpunkt keine Freigabe geben werde. Eine wirkliche Überraschung war es nicht, denn wesentliche Teile der geplanten Features waren weder spezifiziert noch implementiert und getestet.

Der neue Freigabeplan vom September 2010 sieht nun eine Teilung des ursprünglich für Java 7 geplanten Umfangs in eine Version 7 und eine Version 8 von Java „Ende 2012“ vor. Seit November 2010 gibt es auch vier JSRs [1] (Java Specification Requests), die die Neuerungen in Java 7 und 8 beschreiben. In diesem und den nächsten Beiträgen werden wir uns die Neuerungen genauer anschauen. Die Tabellen 1 und 2 zeigen eine Übersicht über die wesentlichen Neuerungen; die vollständige Liste ist hier [2] zu finden.

 

 

JDK 7

 

JSR 336

Java SE 7 Release Contents

Lang

JSR 334

Small language enhancements („Project Coin“)

Vm

JSR 292

Support for dynamically-typed languages („InvokeDynamic“)

Core

Concurrency and collections updates („Fork-Join“ bzw. „jsr166y“)

i18n

Unicode 6.0

 

Locale enhancement

 

Separate user locale and user-interface locale

Ionet

JSR 203

More new I/O APIs for the Java platform („NIO.2“)

 

 

NIO.2 filesystem provider for zip/jar archives

 

 

SCTP (Stream Control Transmission Protocol)

 

 

SDP (Sockets Direct Protocol)

 

 

Use the Windows Vista IPv6 stack

 

 

TLS 1.2

Tabelle 1: Plan für JDK 7

 

 

JDK 8 (Ende 2012 oder später)

 

JSR 337

Java SE 8 Release Contents

Vm

JSR 294

Language and VM support for modular programming

 

A module system for modularizing the JDK („Project Jigsaw“)

Lang

JSR 308

Annotations on Java types

 

Language support for collections

 

JSR 335

Lambda expressions, formerly known as „closures“, and defender methods („Project Lambda“)

Core

Concurrency and collections updates that depend on lambdas („Parallel Arrays“ bzw. „extra166y“)

Tabelle 2: Plan für JDK 8

Worum geht es dabei?

Project Coin

„Project Coin“ ist eine Sammlung kleinerer Spracherweiterungen (bei dem Projektnamen handelt es sich um ein Wortspiel: das englische Wort „coin“ bedeutet einerseits „Münze“, also „Kleingeld“ oder „Kleinigkeit“; andererseits bezeichnet das Verb „to coin“ das „Prägen“ von Münzen oder auch Begriffen). Die Ideen für diese Ergänzungen stammen aus der Java-Community selbst. Sun Microsystems hatte die Community aufgefordert, entsprechende Vorschläge zu machen, und hatte aus der Fülle der Ideen eine Handvoll aufgegriffen. Die Idee dabei war es, die Sprache um Mittel zu erweitern, die nützlich und „klein“ sind.

In den JDK geschafft haben es folgende Vorschläge:

  • Strings in switch-Anweisungen
  • Verbesserte Schreibweisen für numerische Literale
  • Vereinfachungen beim Aufruf von Methoden mit variabler Argumentenliste
  • Verbesserte Type Inferences für Konstruktoren generischer Typen („diamond operator“)
  • Verbessertes Exception Handling
  • Automatic Resource Management
  • Sprachunterstützung für Collections (Java 8)

Die Sprachunterstützung für Collections ist noch nicht implementiert und deshalb nicht für Java 7 vorgesehen, sondern gleich auf Java 8 verschoben worden. Hier ist zu erwarten, dass die später frei gegebene Implementierung von den heutigen Vorschlägen abweichen wird.

Die „Coin“-Features werden wir uns in den nächsten beiden Beiträgen genauer ansehen.

[ header = Seite 2: InvokeDynamic ]

InvokeDynamic

invokedynamic ist eine neue Bytecode-Instruktion, die den Aufruf von Methoden erlaubt, ohne dass geprüft wird, zu welcher Klasse diese Methode gehört, von welchem Typ ihr Returnwert ist oder welche Methodenparameter sie verwendet. Die bisherigen Bytecode-Instruktionen für den Aufruf von Methoden invokevirtual („normale“ Methodenaufrufe), invokestatic (Aufruf statischer Methoden) und invokespecial (Aufruf von Konstruktoren und Superclass-Methoden) verlangen eine genaue Spezifikation der Methodensignatur. Die Bytecode-Verifikation während des Classloadings prüft diese Bytecode-Instruktionen und weist Aufrufe, für die es keine zur Signatur passende Methode gibt, zurück. Lediglich die Instruktion invokeinterface (Aufruf einer Methode über einen Interfacetyp, d. h. ohne dass festgelegt wäre, zu welcher Klasse die Methode gehört) war etwas gnädiger bei der Prüfung.

All diese Bytecode-Instruktionen sind angelegt für eine statisch geprüfte Sprache wie Java, bei der der Typ jedes Objekts und die gesamte Signatur jeder Methode bereits zur Übersetzungszeit feststehen. Mittlerweile gibt es aber zahlreiche Sprachen auf der JVM, die dynamisch geprüft werden und in denen Methoden eben keine zur Übersetzungszeit festgelegte Signatur haben. Für die Implementierung von dynamischen Sprachen auf der JVM waren deshalb zahlreiche Klimmzüge nötig, um die Methodenaufrufe zu bewerkstelligen. Die neue Bytecode-Instruktion invokedynamiclöst diese Probleme. Java-Entwickler werden mit invokedynamic nicht in Berührung kommen, weil der Java-Compiler diese Instruktion nicht verwendet.

Concurrency Utilities

Unter der Bezeichnung „jsr166y“ werden Ergänzungen zum Concurrency Support des JDK verstanden. Beschrieben sind die Neuerungen im JSR 166, den Doug Lea seit Java 5 stetig weiterpflegt. In Java 5 gab es den JSR166, in Java 6 den JSR166x und in Java 7 kommt nun JSR166y hinzu [3]. Es gibt außerdem noch einen Teil JSR166yextra, der auf Java 8 verschoben wurde, weil er ohne das Sprachmittel der Lambdas nicht gut benutzbar ist. Dabei geht es um Parallel Arrays, d. h. um die Parallelisierung von Array-Zugriffen.

Die wesentliche Neuerung für Java 7 ist ein Framework für die Parallelisierung von rekursiven Aufgaben, Fork/Join Framework genannt. Dabei handelt es sich um einen speziellen Thread Pool für Tasks, die sich rekursiv in Subtasks zerlegen, diese Subtasks starten, auf die Teilergebnisse warten und daraus ein Gesamtergebnis produzieren. Da solche Aufgaben voneinander abhängen – jede Task wartet auf das Ergebnis ihrer Subtasks – ist der herkömmliche, bereits seit Java 5 im JDK enthaltene Thread Pool (Klasse ThreadPoolExecutor) ungeeignet. Er ist für voneinander unabhängige Tasks gedacht. Deshalb gibt es mit der Klasse ForkJoinPool eine Thread-Pool-Implementierung, die für das Abarbeiten rekursiver Aufgaben angelegt ist. Die für Java 8 angekündigten Parallel Arrays werden übrigens auf diesem Fork/Join Framework aufsetzen.

Neben dem Fork/Join Framework kommt mit Java 7 die Abstraktion Phaser zum Package java.util.concurrent hinzu. Der Phaser ist eine flexiblere Variante der seit Java 5 existierenden CyclicBarrier. Während sich an einer CyclicBarrier eine fixe Anzahl von Threads trifft und aufeinander wartet, erlaubt der Phaser eine variable Anzahl von beteiligten Parteien.

Eine weitere Neuerung bei den Concurrency Utilities ist die TransferQueue. Dabei handelt es sich um eine Kombination aus einer normalen BlockingQueue und einer SynchronousQueue. Bei Bedarf kann der Producer warten, bis ein Consumer das neue Element abholt (wie bei der SynchronousQueue); alternativ kann er das Element einfach in die Queue legen, ohne auf einen Abholer zu warten (wie bei der normalen BlockingQueue).

Internationalisierung

Mit Java 7 wird eine Reihe von Modernisierungen im Bereich der Internationalisierung berücksichtigt.

  • Unicode 6.0: Java-Programme verwenden den Unicode-Zeichensatz und jeder JDK unterstützt die jeweils aktuelle Version des Unicode-Standards – von Version 1.1.5 im JDK 1.0 bis zu Version 4.0 in J2SE 5.0 und JDK 6. Für Java 7 war zunächst die Unterstützung von Unicode 5.1 geplant, aber durch die Verschiebung des Freigabetermins auf Mitte 2011 wird Unicode 6.0 die aktuelle und damit die vom Java 7 unterstütze Version sein.
  • IETF BCP 47: Die Internet Engineering Task Force (IETF) ist eine Organisation, die sich mit der technischen Weiterentwicklung des Internets befasst. Unter anderem hat sie im Jahr 1995 im RFC 1766 (RFC = Request for Comments) die Kürzel für die Identifikation von Sprachbereichen wie z. B. „de“ für Deutsch und „de-AT“ für deutsch-österreichische Prägung festgelegt. Diese Sprach-Tags werden z. B. in der Klasse java.util.Locale verwendet, deren Implementierung noch heute auf den mittlerweile hoffnungslos veralteten RFC-1766-Festlegungen basiert. Für Java 7 ist geplant, die Klasse java.util.Locale so anzupassen, dass sie den aktuellen IETF-Standard BCP 47 (BCP = Best Current Practice) verwendet. Auch dies ist lediglich eine Anpassung an aktuelle Standards.
  • Trennung zwischen User Locale und User Interface Locale: Locales werden von den verschiedenen JDK-Klassen zu unterschiedlichen Zwecken verwendet: einerseits für die Formatierung von kulturabhängigen Zahlen, Datums-, Zeit- und Währungsangaben und ähnlichem, andererseits für die sprachabhängige Darstellung und Verarbeitungen von Texten, die Anzeige von Benutzeroberflächen und ähnlichem. Hier soll eine Trennung zwischen einer User Locale (oder auch Formatting Locale) und einer User Interface Locale (oder auch Language Locale) vorgenommen werden. Inspiriert ist diese Trennung durch die jüngeren Microsoft-Windows-Systeme, wo es eine ähnliche Unterscheidung gibt.

[ header = Seite 3: NIO.2 ]

NIO.2

Mit „NIO.2“ werden Ergänzungen zum Package java.nio bezeichnet. Die „alte“ I/O im Package java.io gibt es schon, seit es Java gibt, von kleineren Ergänzungen und Korrekturen einmal abgesehen. Mit Java 1.4 ist neue d. h. zusätzliche I/O-Funktionalität hinzugekommen. Dieser Funktionsumfang wurde NIO („new I/O“) genannt und befindet sich in dem Package java.nio. Mit Java 7 kommt nun weitere zusätzliche Funktionalität dazu, die im Java Specification Request [4] beschrieben ist:

Neues File System API: Die NIO.2 liefert ein neues, sehr umfangreiches File System API. Dies ersetzt die bisher eher rudimentäre Funktionalität von java.io.File vollständig und geht weit darüber hinaus. Bestandteil ist des Weiteren ein System Provider Interface (SPI), das es ermöglicht, eigene File-Systeme (und/oder Sichten auf Geräte) so einzubinden, dass sie über das neue File System API zugreifbar sind. Als Bestandteil von Java 7 wird der System Provider Support für ZIP- und RAR-Archive ausgeliefert.

Erweiterungen für asynchrone I/O: Der zweite größere Teil der NIO.2 sind Erweiterungen für asynchrone I/O. Dabei geht es zum einen um ein API für asynchrone I/O, das höher angesetzt ist als das bisherige von java.nio.channels.Selector zur Verfügung gestellte API. Zum anderen geht es um die Ausweitung der asynchronen I/O auf Multicast Datagams und File I/O.

Diverse Protokolle und Standards: Daneben gibt es noch diverse kleinere Ergänzungen, bei denen es um die Unterstützung verschiedener Protokolle und Standards geht.

  • SCTC: Das Stream Control Transmission Protocol (SCTP) [5] ist ein relativ neues Kommunikationsprotokoll, das im TCP/IP-Stack parallel zu TCP und UDP steht. Hierfür wird es eine API-Implementierung in Java 7 geben. Derzeit ist sie nur für Solaris verfügbar, aber eine Portierung auf andere Plattformen wie Windows ist laut Aussage des Project Leads Chris Hegarty [6] nicht mehr viel Arbeit.
  • SDP: Java 7 wird das Socket Direct Protocol [7] (SDP) unter Solaris und Linux unterstützen. Für den Java-Programmierer gibt es kein neues API. SDP kann vielmehr über die bisherigen Network-APIs wie Socket, ServerSocket, SocketChannel, ServerSocketChannel, AsynchronousSocketChannel und Asynchronous ServerSocketChannel nach entsprechender Konfiguration des Systems [8]  genutzt werden.
  • TLS: Java 7 wird über bestehende APIs den Transport-Layer-Security-(TLS-)Standard in der neuen Version 1.2 unterstützen.
  • IPv6: Des Weiteren wird Java 7 die Nutzung des neuen mit Vista eingeführten, IPv6-fähigen Protokoll-Stacks unter Windows unterstützen. Auch dies wird über bestehende APIs verfügbar gemacht.

Project Jigsaw

Bei „Project Jigsaw“ geht es um ein Modulkonzept für Java. Ein bekanntes Defizit von Java ist, dass es keine Module kennt. Man kann heutzutage zwar eine Menge von zusammenhängenden Klassen und Ressourcen z. B. in einer jar-Datei zusammenfassen und hat damit so etwas wie ein Modul, aber es gibt keine Möglichkeit zu beschreiben, was ein Modul anderen Modulen zur Verfügung stellt, was es seinerseits wieder braucht und in welchen Versionen. Das Problem taucht beispielsweise auf, wenn man Software verwendet, die wiederum Software, z. B. „Apache Commons“, verwendet. Wenn nun die verwendete Software unterschiedliche Versionen von Apache Commons braucht, kann man die Commons-Bibliothek nur einmal einbinden. In welcher Version soll man das tun? Da nimmt man üblicherweise die jüngste und hofft, dass sie abwärts-kompatibel ist. Wirklich befriedigend ist diese Situation nicht. Was man braucht, ist zumindest eine klare Beschreibung von Export-, Import- und Versionsbeziehungen. Das ist eines der Probleme, die ein Modulkonzept lösen soll.

Über die Modularisierung hat es heftige Diskussionen gegeben. Sun Microsystems hatte ursprünglich vor, im Rahmen des JSR 294 (Superpackages) und JSR 277 (Java Module System) ein Modulkonzept in Java einzuführen. OSGi (Open Services Gateway Initiative – JSR 291) enthält unter anderem auch ein Modulkonzept, dort „Bundle“ statt „Module“ genannt. Lange und heftige Auseinandersetzungen mit der OSGi-Fraktion über Kompatibilität bzw. Inkompatibilität, Funktionsumfang, usw. haben am Ende dazu geführt, dass Sun Microsystems die Aktivitäten für JSR 294 und 277 Ende 2008 vorerst eingestellt hat.

Stattdessen wurde die Entwicklung eines einfachen Modulkonzepts gestartet, mit dessen Hilfe der JDK selbst modularisiert werden kann. Wenn JDK-Benutzer dieses Modulkonzept hilfreich finden, können sie es für ihre eigene Software gerne nutzen. Dieses Konzept bzw. seine Implementierung ist „Project Jigsaw“ und wird mit Java 8 freigegeben.

[ header = Seite 3: Type Annotations ]

Type Annotations

Java 8 wird die so genannten „Type Annotations“ unterstützen. Dabei handelt es sich um eine Änderung an der Sprache, die die Verwendung von Annotationen an deutlich mehr Stellen erlaubt, als es bisher der Fall war. Bislang war die Verwendung von Annotationen im Quellcode beschränkt. Es konnten lediglich Packages, Typen, Methoden und Konstruktoren, Felder, lokale Variablen, Methodenparameter und Enumeratoren annotiert werden. In Java 8 wird es erlaubt sein, Annotationen überall dort zu verwenden, wo Typen erlaubt sind. Zum Beispiel darf man dann Konstrukte wie

Map<@NonNull String, @NonEmpty List<@Readonly Document>> files;
@NonNull Object @Nullable [] array;

schreiben, was bislang syntaktisch unzulässig ist, weil weder zu den Typparametern in generischen Typen noch zum Elementtyp von Arrays Annotationen hinzugefügt werden dürfen.

Das Ziel dieser Spracherweiterung ist es, die Annotationen ganz generell als Typqualifikatoren verwenden zu können. Mithilfe der Annotationen kann in Java 8 das Typsystem der Sprache Java erweitert werden – ohne die Sprache ändern zu müssen – indem man Typen mithilfe von Annotationen näher beschreiben kann. Diese Änderung der Java-Syntax wurde im JSR 308 [9] beschrieben, der zwar bislang nicht formal verabschiedet wurde, aber in Java 8 implementiert werden soll.

Wozu braucht man das? Ohne Werkzeuge, die diese neuen Möglichkeiten nutzen, machen die Typannotationen keinen Sinn. Deshalb werden begleitend zu den beschriebenen Sprachänderungen statische Analysewerkzeuge entwickelt, die anhand bestimmter Annotationen Fehler im Quellcode aufzuspüren. Ein Beispiel für solche Annotationen sind @NonNull und @Nullable. Die betreffenden Werkzeuge sollen verhindern, dass einer @NonNull-Variablen (die nicht null werden darf) der Wert null zugewiesen wird oder dass eine @Nullable-Variable (die den Wert null haben könnte) ohne Prüfung auf != null dereferenziert wird. Diese Werkzeuge werden aber nicht Bestandteil von Java 8 sein, sondern Add-ons, die man zusätzlich herunterladen und verwenden kann.

Project Lambda

Beim „Project Lambda“ (vormals „Closures“) geht es um ein neues Sprachmittel in Java, das aus funktionalen Programmiersprachen stammt. Wenn man heutzutage in Java eine Funktionalität formulieren und als Parameter übergeben möchte, dann muss man ein Interface definieren und eine Klasse, die das Interface implementiert. Beispiel: Wenn man eine Funktionalität asynchron in einem anderen Thread ausführen will, muss man eine Klasse schreiben, die das Interface Runnable mit seiner run()-Methode implementiert, in der run()-Methode wird die eigentliche Funktionalität formuliert, dann wird ein Objekt von neuen Typ alloziert und einem Thread oder Thread-Pool zur Ausführung übergeben. Eigentlich geht es aber nur um das, was die run()-Methode tut. Der syntaktische Überbau für das Runnable-Interface, die implementierende Klasse und die Objektkonstruktion ist eigentlich komplett überflüssig. Ähnliche Situationen findet man bei der Implementierung von Callbacks oder Listener Interfaces oder ganz allgemein bei Interfaces mit nur einer Methode. Um die Syntax zu vereinfachen, soll es Lambda-Ausdrücke geben. Anstelle von

new Thread(new Runnable { public void run() { System.out.println (“Hello World!”); } }).start();

würde man lediglich sagen

new Thread( #{ System.out.println (“Hello World!”) ).start();

Der mit „#“ eingeleitete Ausdruck wäre das Lambda und beschreibt nur noch das Wesentliche, nämlich die Funktionalität. Das ist eine sehr vereinfachte Darstellung von Lambdas. Im Zusammenhang mit diesem neuen Sprachmittel ist noch weit mehr diskutiert worden und es wird auch noch immer diskutiert über die Syntax und die Mächtigkeit des Sprachmittels. Inspiriert sind die Lambdas von entsprechenden Konstrukten in funktionalen Programmiersprachen, die insbesondere durch neue hybride Sprachen wie Scala und Skriptsprachen wie Groovy populär geworden sind.

Das Sprachmittel der Lambdas ist in den Jahren 2006 bis 2008 sehr heftig diskutiert worden und es gab gleich drei konkurrierende Vorschläge dafür [10], damals noch unter der Bezeichnung „Closures“. Wegen des kontroversen Ansatzes der verschiedenen Vorschläge stagnierte das Thema für mehr als ein Jahr und es sah zunächst so aus, als wären Lambdas/Closures für Java gar kein Thema mehr. Im November 2009 wurde die Idee wieder aufgegriffen und in Java 8 sollen Lambdas dann verfügbar sein [11].

Lambda-Ausdrücke werden u. a. für die ParallelArrays gebraucht, die ebenfalls mit Java 8 freigegeben werden sollen. Die ParallelArrays sind ein Framework, dem man nur noch sagen muss, welche Funktionalität auf jedes einzelne Array-Element angewandt werden soll, und das dann für die parallele Ausführung sorgt. Die Lambdas würden die Benutzung der ParallelArrays drastisch vereinfachen, denn den syntaktischen Überbau für die Beschreibung der Funktionalität in Form von Interfaces und implementierenden Klassen könnte man mit Lambdas komplett eliminieren.

Zusammenfassung

In diesem Beitrag haben wir eine Übersicht über die neuen und geplanten Sprachmittel und JDK-Erweiterungen in Java 7 und Java 8 gegeben. In den folgenden Beiträgen werden wir einige der Neuerungen näher diskutieren.

Geschrieben von
Angelika Langer
Angelika Langer
  Angelika Langer arbeitet selbstständig als Trainer mit einem eigenen Curriculum von Java- und C++-Kursen. Kontakt: http://www.AngelikaLanger.com.
Klaus Kreft
Klaus Kreft
  Klaus Kreft arbeitet selbstständig als Consultant und Trainer. Kontakt: http://www.AngelikaLanger.com.
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.