Warum Properties extends Hashtable<Object, Object> und nicht Hashtable<String, String>?

Von der Intuition her ist von der Vererbung class Properties extends Hashtable<String, String> naheliegend, doch hat Sun nicht gewollt. Der Grund hat gar nicht so sehr mit Properties selbst zu tun, sondern mit der Basisklasse Hashtable und gewählten Umsetzung der Generics und der gewünschten Kompatibilität. Von Java 1.0 bis Java 1.4 hat die Klasse Hashtable eine Methode put(Object, Object). Ab Java 5 wird Object durch generische Typparameter ersetzt, sodass es in Hashtable heißt: put(K, V). Wenn nun Properties extends Hashtable<String,String> ist, dann wird die Hinzufügemethode zu put(String, Sting). Das wäre nicht mehr kompatibel zu put(Object, Object) vor Java 5. Also haben die Sun-Entwickler Properties extends Hashtable<Object, Object> geschrieben, auch wenn die put(…)-Methode überhaupt nicht verwendet werden soll, sondern setProperty(…). Da Generics nur ein „Trick“ des Compilers sind, lässt sich über den Raw-Typ tricksen:

Properties props = new Properties();

@SuppressWarnings( {"rawtypes", "unchecked"} )

Map<String, String> map = (Map) props;

Iterator vom Stream besorgen

Sich einen Iterator von einem Stream geben zu lassen ist nützlich, weil dann der Zeitpunkt des Konsumierens vom Zeitpunkt des Stream-Aufbaus getrennt werden kann. Es ist nicht einfach mehrere Streams gleichzeitig abzulaufen, doch mit Iteratoren funktioniert das. Zudem lässt sich in Stream mit einer Generator-Funktion einfach aufbauen, in Iterator aber nicht.

Beispiel: Aus zwei Streams sollen jeweils alterrnierend das nächste Element konsumiert und ausgegeben werden.

Iterator<Integer> iterator1 = Stream.of( 1, 3, 5 ).iterator();

Iterator<Integer> iterator2 = Stream.of( 2, 4, 6, 7, 8 ).iterator();




while ( iterator1.hasNext() || iterator2.hasNext() ) {

  if ( iterator1.hasNext() )

    System.out.println( iterator1.next() );

  if ( iterator2.hasNext() )

    System.out.println( iterator2.next() );

}

Iterator ist ein Datentyp, der häufig in der Rückgabe verwendet wird, seltener als Parametertyp. Mit stream.iterator() ist es aber möglich, die Daten vom Stream genau an solchen Stellen zu übergeben. Einen Stream in einen Iterator zu konvertieren, um diesen dann mit hasNext()/next() abzulaufen, ist wenig sinnvoll, hierfür bietet sich genauso gut forEach(…) auf dem Stream an.

Stream ist nicht Iterable

Der Typ Stream bietet eine Methode iterator(), erweitert jedoch die Schnittstelle Iterable nicht. In der Javadoc ist bei iterator() die Bemerkung „terminale Operation“ vermerkt, denn der Iterator saugt den Stream leer, sodass ein zweiter iterator()-Aufruf auf einem Stream nicht möglich ist. Bei Klassen, die Iterable implementieren, muss ein Aufruf von iterator() beliebig oft möglich sein. Bei Streams ist das nicht gegeben, da die Streams selbst nicht für die Daten stehen wie eine Collection, die daher Iterable ist.

Iterator in Stream umwandeln

Ist auf der anderen Seite ein Iterator gegeben, lässt sich dieser nicht direkt in einen Stream bringen. Iteratoren können wie Streams unendlich sein, und es gibt keinen Weg, die Daten eines Iterators als Quelle zu benutzen. Natürlich ist es möglich, den Iterator abzulaufen und daraus einen neuen Stream aufzubauen, dann muss der Iterator aber endlich sein.

Beispiel: Die Methode ImageIO.getImageReadersBySuffix(String) liefert einen Iterator von ImageReader-Objekten – sie sollen über einen Strom zugänglich sein:

Builder<ImageReader> builder = Stream.builder();
 for ( Iterator<ImageReader> iter = ImageIO.getImageReadersBySuffix( "jpg" );
       iter.hasNext(); )
   builder.add( iter.next() );
 Stream<ImageReader> stream = builder.build();
 System.out.println( stream.count() );    // 1

Einen anderen Weg geht StreamSupport.

Ist eine alte Enumeration gegeben, hilft Collections.list(enumeration).stream(), denn list(…) liefert eine ArrayList mit allen Einträgen; list(Iterator) gibt es da hingegen nicht.

iterator() von BaseStream und PrimitiveIterator.OfXXX

Die Schnittstelle Stream deklariert keine abstrakte iterator()-Methode, sondern bekommt die Methode vom Obertyp BaseStream vererbt. BaseStream ist insgesamt Basistyp von:

  • Stream<T>, DoubleStream, IntStream, LongStream

Alle diese drei Typen haben damit iterator()-Methdoden, doch die Rückgaben sind unterschiedlich:

Typ iterator()-Methdoden und Rückgabe
Stream<T> Iterator<T> iterator()
DoubleStream PrimitiveIterator.OfDouble iterator()
IntStream PrimitiveIterator.OfInt iterator()
LongStream PrimitiveIterator.OfInt iterator()

Unterschiedliche Rückgaben der Iteratoren

PrimitiveIterator ist eine Schnittstelle aus dem Paket java.util mit eben drei inneren statischen Schnittstellen: OfDouble, OfInt und OfLong, die PrimitiveIterator erweiten. Jeder dieser drei inneren Typen hat eigene, aber symmetrische Methoden:

  • default void forEachRemaining(Consumer<? super WrapperTyp> action)
  • default void forEachRemaining(WrapperTypConsumer action)
  • default WrapperTyp next()
  • PrimitiverTyp nextPrimitiverTyp()

Statt WrapperTyp und PrimitiverTyp ist dann Double, Integer, Long und double, int, double einzusetzen.

Beispiel: Ein vom Stream abgeleiter Iterator besorgt Zahlen. Diese werden in einem anderen Stream eingesetzt.

PrimitiveIterator.OfInt counter =

  IntStream.iterate( 1, Math::incrementExact ).iterator();

Stream.of( "Telegram", "WhatsApp", "Facebook Messenger", "Insta" )

      .map( s -> counter.nextInt() + ". " + s )

      .forEach( System.out::println );

jdk-11-ea+2 freigegeben

Die größte Änderung ist, was angekündigt wurde:

These builds include JEP 320 (Remove the Java EE and CORBA Modules) [1],
so they're significantly smaller (nine fewer modules, 22 fewer megabytes
on Linux/x64).

- Mark

Weitere Infos und Download unter http://jdk.java.net/11/. Folgende Änderungen gibt es:

Changeset Bug ID Synopsis
d9fce53461a1 8197812 (ref) Data race in Finalizer
c38163717870 8198227 Fix COMPARE_BUILD after forest consolidation
329428e095b6 8198306 Add post custom extension hooks to two launchers
67cdc215ed70 8198228 Spec clarification: j.u.Locale.getDisplayName()
edaa989b4e67 8058965 Remove IPv6 support from TwoStacksPlainSocketImpl [win]
01237b276b8b 8198318 Make build comparisons clean again
7f9c3cd11e97 8170120 jimage throws IOException when the given file is not a jimage file
0a185d6fafa1 8198379 tools/jimage/JImageListTest.java failing
b417304c811b 8198380 tools/jimage/JImageExtractTest.java failing
42cec55157fa 8198417 Exclude tools/jimage/JImageExtractTest.java and tools/jimage/JImageListTest.java on Windows
37beaca49e63 8194922 jlink –exclude-resources should never exclude module-info.class
18debf414948 8198425 make/Main.gmk Add extra extension/override points to the make file
c7e84c0a51c3 8198328 Create devkit for Solaris with developer studio 12.6 and Solaris11.3
916690b5edc9 8194892 add compiler support for local-variable syntax for lambda parameters
576e024f10b6 8198418 Invoke LambdaMetafactory::metafactory exactly from the BootstrapMethodInvoker
906025796009 8198441 Replace native Runtime::runFinalization0 method with shared secrets
b75c9e2e3b1f 8198450 Make jdk.internal.vm.compiler/module-info.java.extra reproducable
1913e7fc6be9 8198301 jdk11+1 was built as ‚fcs‘ instead of ‚ea‘
b2bba53b079d 8198303 jdk11+1 was build with incorrect GA date as 2018-03-20
02404e27d356 8198479 JDK build is broken by 8194892
847a988152b8 8194154 System property user.dir should not be changed
cc30928a834e 8198385 Remove property sun.locale.formatasdefault
28d8fc8cd3cd 8190904 Incorrect currency instance returned by java.util.Currency.getInstance()
b1a5b4ad7427 8198523 Refactor BootstrapMethodInvoker to further avoid runtime type checks
b25eb74ec283 8197439 Crash with -XDfind=lambda for anonymous class in anonymous class.
9e3f2ec326ba 8198502 Exception at runtime due to lambda analyzer reattributes live AST
20358c9f72c1 8198563 Test langtools/tools/javac/analyzer/AnonymousInAnonymous.java failing after JDK-8198502
03ae177c26b0 8198512 compiler support for local-variable syntax for lambda parameters

Release Notes Since build 1  Integrations

core-libs/java.util.concurrent

 ThreadPoolExecutor should not specify a dependency on finalizationPrevious versions of ThreadPoolExecutor had a finalize method that shut down the thread pool, but in this version the finalize method does nothing. This should have no visible effect unless a subclass explicitly invokes the finalize method and relies on the executor being shutdown.

security-libs/java.security

 jarsigner should print when a timestamp will expireThe jarsigner tool now shows more information about the lifetime of a timestamped JAR. New warning and error messages are displayed when a timestamp has expired or is expiring within one year.

Callable oder Runnable mit FutureTask ummanteln

Die Klasse java.util.concurrent.FutureTask implementiert Future, Runnable und RunnableFuture und wird intern von der Java-Bibliothek verwendet, wenn wir mit submit(…) etwas beim ExecutorService absetzen. Auch wir können den Typ direkt als Wrapper um ein Callable oder Runnable nutzen, denn es gibt praktische Callback-Methoden, die wir überschreiben können, etwa done(), wenn eine Berechung fertig ist.

Dazu ein Beispiel: Ein Callable liefert den Namen des Benutzers. Ein FutureTask legt sich um dieses Callable und bekommt mit, wann das Callable fertig ist und modifiziert dann den Benutzernamen und gibt weiterhin eine Meldung aus.

Callable<String> username = () -> System.getProperty( "user.name" );

FutureTask<String> wrappedUsername = new FutureTask<>( username ) {

  @Override

  protected void done() {

    try {

      System.out.printf( "done: isDone=%s, isCancelled=%s%n", isDone(), isCancelled() );

      System.out.println( "done: get=" + get() );

    }

    catch ( InterruptedException | ExecutionException e ) { /* Ignore */ }

  }

  @Override

  protected void set( String v ) {

    System.out.println( "set: " + v );

    super.set( v.toUpperCase() );

  }

};

ExecutorService scheduler = Executors.newCachedThreadPool();

scheduler.submit( wrappedUsername );

System.out.println( "main: " + wrappedUsername.get() );

scheduler.shutdown();

Wichtig in der Nutzung ist, nicht die Rückgabe vom submit(…) auszuwerten, was wir normalerweise machen, sondern das übergebene FutureTask zu erfragen.

Die Ausgaben vom Programm sind oft ein wenig durcheinander:

set: Christian
done: isDone=true, isCancelled=false
done: get=CHRISTIAN
main: CHRISTIAN

Die Reihenfolge in den Aufrufen ist immer so: Der FutureTask stellt die Fertigstellung vom Callable fest und ruft set(…) auf. Anschließend done().

Tor auf mit CountDownLatch

Die Klasse CountDownLatch hilft Threads an einem gewissen Punkt zusammenzukommen und dann weiterzumachen. Das kann ein Thread sein, der auf das Fertigwerden von N anderen Threads wartet oder N Threads, die ein Signal zum Loslaufen bekommen. CountDownLatch ist mit einem Zähler assoziiert, der sich herunterzählen lässt. Auf der anderen Seite wartet die andere Partei darauf, dass der Zähler 0 wird, um fortzuführen. Mit diesem Wissen ergibt auch der Klassenname Sinn: „count down“ heißt auf deutsch „runterzählen“ und „latch“ ist das englische Wort für Falle, Riegel, Sperrklinke; nach dem erfolgreichen runterzählen entsperrt die Klinke.

Ein Beispiel. Wir wollen prüfen, ob Hosts im Internet erreichbar sind. Der Zähler vom CountDownLatch entspricht der Anzahl der zu überprüfenden Hosts. Für jeden Host starten wir einen Thread. Ist der Host erreichbar, wird CountDownLatch mit countDown() herunterzählt. Am Ende waren wir jedoch nicht mit await() ob wir bei 0 angekommen sind – Hosts können nicht erreichbar sein – sondern wir warten eine gewisse Zeit mit der überladenen Methode await(long timeout, TimeUnit unit). Ist der Zähler nach der Zeit nicht 0 gibt es keine Ausnahme, sondern wir erfragen den Zähler um herauszufinden, wie viele Hosts erreichbar waren.

List<String> hosts = List.of( "popel.nase", "tutego.de" );

CountDownLatch latch = new CountDownLatch( hosts.size() );



for ( String host : hosts ) {

  new Thread( () -> {

    try {

      if ( InetAddress.getByName( host ).isReachable( 900 /* ms */ ) )

        latch.countDown();

    }

    catch ( IOException e ) { /* ignore */ }

  } ).start();

}



try {

  if ( latch.await( 1, TimeUnit.SECONDS ) )

    System.out.println( "Alle Hosts erreicht" );



  System.out.printf( "%d von %d Hosts nicht erreicht", latch.getCount(), hosts.size() );

}

catch ( InterruptedException e ) {

  e.printStackTrace();

}

Der CountDownLatch hat nur eine Methode zum Herunterzählen, nicht zum wieder erhöhen. Damit ist klar, dass sich ein heruntergezähltes Objekt nicht mehr verwenden kann.

Java sollte „Inkubator“-Features bekommen.

Das bedeutet, es gibt Syntaxerweiterungen, aber die sind erst mal zum Testen.

http://openjdk.java.net/jeps/12

An incubating language or VM feature is a new feature of the Java SE Platform that is fully specified, fully implemented, and yet impermanent. It is available in a JDK feature release to provoke developer feedback based on real world use; this may lead to it becoming permanent in a future Java SE Platform.

In der Mailliste fragen die Eclipse-Bauer schon nach, ob das verpflichtend ist … es wäre blöd, wenn man sich bei den JDT viel Mühe gibt, und dann wird das doch nicht übernommen: http://mail.openjdk.java.net/pipermail/jdk-dev/2018-February/000642.html

JEP-12 ist allerdings noch nicht bestätigt.

 

Inselupdate: switch hat ohne Unterbrechung Durchfall

Bisher haben wir in die letzte Zeile eine break-Anweisung gesetzt. Ohne ein break würden nach einer Übereinstimmung alle nachfolgenden Anweisungen ausgeführt. Sie laufen somit in einen neuen Abschnitt herein, bis ein break oder das Ende von switch erreicht ist. Da dies vergleichbar mit einem Spielzeug ist, bei dem Kugeln von oben nach unten durchfallen, nennt sich dieses auch Fall-through. Ein häufiger Programmierfehler ist, das break zu vergessen, und daher sollte ein beabsichtigter Fall-through immer als Kommentar angegeben werden.

Über dieses Durchfallen ist es möglich, bei unterschiedlichen Werten immer die gleiche Anweisung ausführen zu lassen. Das nutzt auch das nächste Beispiel, das einen kleinen Parser für einfache Datumswerte realisiert. Der Parser soll mit drei unterschiedlichen Datumsangeben umgehen können, je ein Beispiel:

  • „18 12“: Jahr in Kurzform, Monat
  • „2018 12“: Jahr, Monat
  • „12“: Nur Monat, es soll das aktuelle Jahr implizit gelten
public class SimpleYearMonthParser {

@SuppressWarnings( "resource" )

public static void main( String[] args ) {

String date = "17 12";

int month = 0, year = 0;

java.util.Scanner scanner = new java.util.Scanner( date );

switch ( date.length() ) {

case 5:  // YY MM

year = 2000;

// Fall-through

case 7: // YYYY MM

year += scanner.nextInt();

// Fall-through

case 2: // MM

month = scanner.nextInt();

if ( year == 0 )

year = java.time.Year.now().getValue();

break;

default :

System.err.println( "Falsches Format" );

}

System.out.println( "Monat=" + month + ", Jahr=" + year );

}

}

In dem Beispiel bestimmt eine case-Anweisung über die Länge, wie der Aufbau ist. Ist die Länge 5, so ist die Angabe des Jahres verkürzt und wir initialisieren das Jahr mit 2000, um im folgenden Schritt mit Hilfe vom Scanner das Jahr einzulesen. Zu diesem Schritt wären wir auch direkt gekommen, wenn die Länge der Eingabe 7 gewesen wäre, also das Jahr vierstellig gewesen wäre. Damit ist der Jahresanteil geklärt, es bleibt die Monate zu parsen. Kommen wir direkt über einen String der Länge 2, ist vorher kein Jahr gesetzt, wir bekommen über java.time.Year.now().getValue() das aktuelle Jahr, andernfalls überschreiben wir die Variable nicht.

Was sollte der Leser von diesem Beispiel mitnehmen? Eigentlich nur Kopfschütteln für eine schwer zu verstehende Lösung. Das Durchfallen ist eigentlich nur zur Zusammenfassung mehrerer case-Blöcke sinnvoll zu verwenden.

Sprachvergleich *

Obwohl ein fehlendes break zu lästigen Programmierfehlern führt, haben die Entwickler von Java dieses Verhalten vom syntaktischen Vorgänger C übernommen. Eine interessante andere Lösung wäre gewesen, das Verhalten genau umzudrehen und das Durchfallen explizit einzufordern, zum Beispiel mit einem Schlüsselwort. Dazu gibt es eine interessante Entwicklung: Java »erbt« diese Eigenschaft von C(++), die wiederum erbt sie von der Programmiersprache B. Einer der »Erfinder« von B ist Ken Thompson, der heute bei Google arbeitet und an der neuen Programmiersprache Go beteiligt ist. In Go müssen Entwickler ausdrücklich die fallthrough-Anweisung verwenden, wenn ein case-Block zum nächsten weiterleiten soll. Das gleiche gilt für die neue Programmiersprache Swift; auch hier gibt es die Anweisung fallthrough. Selbst in C++ gibt es seit dem Standard C++17 das Standard-Attribut [[fallthrough]][1] – Attribute sind mit Java-Annotationen vergleichbar ist; es steuert den Compiler, bei einem Durchfallen keine Warnung anzuzeigen.

Stack-Case-Labels

Stehen mehrere case-Blöcke untereinander, um damit Bereiche abzubilden, nennt sich das auch Stack-Case-Labels. Nehmen wir an, eine Variable hour steht für eine Stunde am Tag und wir wollen herausfinden, ob Mittagsruhe, Nachtruhe oder Arbeitszeit ist:

int hour = 12;

switch ( hour ) {

// Nachtruhe von 22 Uhr bis 6 Uhr

  case 22:

  case 23:

  case 24: case 0:

  case 1: 

  case 2: 

  case 3: 

  case 4:

  case 5: 

System.out.println( "Nachtruhe" );

break;

// Mittagsruhe von 13 bis 15 Uhr

  case 13:

  case 14:  

System.out.println( "Mittagsruhe" );

break;

default :

System.out.println( "Arbeiten" );

break;

}

[1]      http://en.cppreference.com/w/cpp/language/attributes

 

Herunterladen der JDK 10 Early-Access Builds

Das ist unter http://jdk.java.net/10/ möglich. Die Javadoc liegt unter https://download.java.net/java/jdk10/docs/api/overview-summary.html. Release Notes unter http://jdk.java.net/10/release-notes

Interessanter ist:

tools/javadoc(tool)

 Provide a new comment tag to specify the summary of an API description.

By default, the summary of an API description is inferred from the first sentence, which is determined by using either a simple algorithm or java.text.BreakIterator. But, the heuristics are not always correct, and can lead to incorrect determination of the end of the first sentence. A new inline tag {@summary ...} is now available, to explicitly specify the text to be used as the summary of the API description. Please refer to Documentation Comment Specification for the Standard Doclet.

security-libs/java.security

 Remove policytool

The policytool security tool has been removed from the JDK.

Auch Eclipse kann mittlerweile schon zumindest Java 10 im Dialog einstellen, einige Updates wurden gemacht, siehe https://bugs.eclipse.org/bugs/show_bug.cgi?id=529875.

Feature-Release vs. zeitorientiertes Release (ab Java 10)

20 Jahre lang bestimmten Features die Freigabe von neuen Java-Versionen; die Entwickler setzten bestimmte Neuerungen auf die Wunschliste, und wenn alle Features realisiert und getestet waren, erfolgte die allgemeine Verfügbarkeit (eng. general availability, kurz GA). Hauptproblem dieses Feature-basierten Vorgehensmodells waren die Verzögerungen, die mit Problemen bei der Implementierung einhergingen. Vieldiskutiert war das Java 9-Release, weil es unbedingt ein Modulsystem enthalten sollte.

Die Antwort auf diese Probleme, und der Wusch der Java-Community nach häufigeren Releases, beantwortet Oracle mit der „JEP 322: Time-Based Release Versioning“[1]. Vier Releases sind im Jahr geplant:

  • Im März und September erscheinen Haupt-Releases, wie Java 10, Java 11.
  • Updates erscheinen einen Monat nach einem Haupt-Release und dann im Abstand von drei Monaten. Im April und Juli erscheinen folglich Updates 10.0.1 und 10.0.2. Für Java 11 wären das Oktober 2018 und Januar 2019.

Anders gesagt: Im Halbjahresrhythmus gibt es Updates, die es Oracle erlauben, in der schnelllebigen IT-Zeit die Bibliotheken weiter zu entwickeln und neue Spracheigenschaften zu integrieren. Kommt es zu Verzögerungen, hält das nicht gleich das ganze Release auf. Java 10 erscheint als erste Version im März 2018 nach diesem Modell.[2]

[1]      http://openjdk.java.net/jeps/322

[2] http://openjdk.java.net/projects/jdk/10/

JEP Draft für „Raw String Literals“ in Java

In der Diskussion ist der „Back-Tick“, sodass es so aussehen würde:

File Paths Example

Traditional String Literals Raw String Literals
Runtime.getRuntime().exec("\"C:\\Program Files\\foo\" bar");
Runtime.getRuntime().exec(`"C:\Program Files\foo" bar"`);

Multi-line Example

Traditional String Literals Raw String Literals
String html = "<html>\n"
              "    <body>\n" +
              "		    <p>Hello World.</p>\n" +
              "    </body>\n" +
              "</html>\n";
String html = `<html>
                   <body>
                       <p>Hello World.</p>
                   </body>
               </html>
              `;

Regular Expression Example

Traditional String Literals Raw String Literals
System.out.println("this".matches("\\w\\w\\w\\w"));
System.out.println("this".matches(`\w\w\w\w`));

Output:

true

Polyglot Example

Traditional String Literals Raw String Literals
String script = "function hello() {\n" +
                "   print(\'\"Hello World\"\');\n" +
                "}\n" +
                "\n" +
                "hello();\n";
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
Object obj = engine.eval(script);
String script = `function hello() {
                    print('"Hello World"');
                 }
hello();
            `

ScriptEngine engine = new ScriptEngineManager().getEngineByName(„js“); Object obj = engine.eval(script);

Output:

"Hello World"

Database Example

Traditional String Literals Raw String Literals
String query = "SELECT EMP_ID, LAST_NAME\n" +
               "FROM EMPLOYEE_TBL\n" +
               "WHERE CITY = 'INDIANAPOLIS'\n" +
               "ORDER BY EMP_ID, LAST_NAME;\n";
String query = `SELECT EMP_ID, LAST_NAME
                FROM EMPLOYEE_TB
                WHERE CITY = 'INDIANAPOLIS'
                ORDER BY EMP_ID, LAST_NAME;
               `;

Ich bin gespannt, ob das in Java 10 kommen wird. Ich dachte schon, dass Java 10 Release wird eher klein, doch zusammen mit den var-Variablen sind das zwei kleine, aber bedeutende Sprachänderungen.

Details unter http://openjdk.java.net/jeps/8196004.

Warum „können“ Arrays so wenig?

Arrays haben ein Attribut length und eine Methode clone() sowie die von Object geerbten Methoden. Das ist nicht viel. Für Arrays gibt es keine Klassendeklaration, also auch keine .class-Datei, die Methoden deklariert. Es gibt auch keinen Java-Code wie bei anderen Klassen wie String, Arrays oder System, die mit Javadoc dokumentiert sind und folglich in der API-Dokumentation auftauchen. Da es unendliche viele Array-Typen gibt – hinter jedem beliebigen Typ kann [] gesetzt werden – würde das auch unendlich viele Klassendeklarationen nach sich ziehen.

Das, was Arrays können, ist in der Java Sprachdefinition (JLS) festgeschrieben. Bei jeder neuen Methode oder Änderung müsste die JLS angepasst werden, was unpraktisch ist. Natürlich wären Methoden wie sort(…), indexOf(…) praktisch, aber die Beschreibung will Oracle aus der JLS heraushalten und sind in eine Extraklasse Arrays gewandert.

Aktuelles zu Java 10

Nach Java 9 wird uns Java 10 beglücken. Die Zeitleiste sieht so aus:

2017/12/14 Rampdown Phase One
2018/01/11 All Tests Run
2018/01/18 Rampdown Phase Two
2018/02/22 Final Release Candidate
2018/03/20 General Availability

Java 10 ist laut http://openjdk.java.net/projects/jdk/10/ ab heute in der „Rampdown Phase One“ (http://openjdk.java.net/projects/jdk8/milestones#Rampdown_start):

  • Rampdown — Phases in which increasing levels of scrutiny are applied to incoming changes. In phase 1, only P1-P3 bugs can be fixed. In phase 2 only showstopper bugs can be fixed.

Neuerungen dir wir für Java 10 erwarten können, beschrieben im JEP:

286: Local-Variable Type Inference
296: Consolidate the JDK Forest into a Single Repository
304: Garbage-Collector Interface
307: Parallel Full GC for G1
310: Application Class-Data Sharing
312: Thread-Local Handshakes
313: Remove the Native-Header Generation Tool (javah)
314: Additional Unicode Language-Tag Extensions
316: Heap Allocation on Alternative Memory Devices
317: Experimental Java-Based JIT Compiler
319: Root Certificates
322: Time-Based Release Versioning

Es wird auch Java 10, Java 11, usw. heißen und nicht, wie vorher angedacht, Java 18, etc. nach Jahreszahlen. Aus dem http://openjdk.java.net/jeps/322:

  • $FEATURE is incremented every six months: The March 2018 release is JDK 10, the September 2018 release is JDK 11, and so forth.